<!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <title>&#x4f5c;&#x54c1;&#x6a21;&#x5757;&#x529f;&#x80fd;&#x9700;&#x6c42;&#x6587;&#x6863;</title>
            <style>
/* From extension vscode.github */
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

.vscode-dark img[src$=\#gh-light-mode-only],
.vscode-light img[src$=\#gh-dark-mode-only],
.vscode-high-contrast:not(.vscode-high-contrast-light) img[src$=\#gh-light-mode-only],
.vscode-high-contrast-light img[src$=\#gh-dark-mode-only] {
	display: none;
}

</style>
            <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex/dist/katex.min.css">
<link href="https://cdn.jsdelivr.net/npm/katex-copytex@latest/dist/katex-copytex.min.css" rel="stylesheet" type="text/css">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/markdown.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/highlight.css">
<style>
            body {
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', system-ui, 'Ubuntu', 'Droid Sans', sans-serif;
                font-size: 14px;
                line-height: 1.6;
            }
        </style>
        <style>
.task-list-item {
    list-style-type: none;
}

.task-list-item-checkbox {
    margin-left: -20px;
    vertical-align: middle;
    pointer-events: none;
}
</style>
<style>
:root {
  --color-note: #0969da;
  --color-tip: #1a7f37;
  --color-warning: #9a6700;
  --color-severe: #bc4c00;
  --color-caution: #d1242f;
  --color-important: #8250df;
}

</style>
<style>
@media (prefers-color-scheme: dark) {
  :root {
    --color-note: #2f81f7;
    --color-tip: #3fb950;
    --color-warning: #d29922;
    --color-severe: #db6d28;
    --color-caution: #f85149;
    --color-important: #a371f7;
  }
}

</style>
<style>
.markdown-alert {
  padding: 0.5rem 1rem;
  margin-bottom: 16px;
  color: inherit;
  border-left: .25em solid #888;
}

.markdown-alert>:first-child {
  margin-top: 0
}

.markdown-alert>:last-child {
  margin-bottom: 0
}

.markdown-alert .markdown-alert-title {
  display: flex;
  font-weight: 500;
  align-items: center;
  line-height: 1
}

.markdown-alert .markdown-alert-title .octicon {
  margin-right: 0.5rem;
  display: inline-block;
  overflow: visible !important;
  vertical-align: text-bottom;
  fill: currentColor;
}

.markdown-alert.markdown-alert-note {
  border-left-color: var(--color-note);
}

.markdown-alert.markdown-alert-note .markdown-alert-title {
  color: var(--color-note);
}

.markdown-alert.markdown-alert-important {
  border-left-color: var(--color-important);
}

.markdown-alert.markdown-alert-important .markdown-alert-title {
  color: var(--color-important);
}

.markdown-alert.markdown-alert-warning {
  border-left-color: var(--color-warning);
}

.markdown-alert.markdown-alert-warning .markdown-alert-title {
  color: var(--color-warning);
}

.markdown-alert.markdown-alert-tip {
  border-left-color: var(--color-tip);
}

.markdown-alert.markdown-alert-tip .markdown-alert-title {
  color: var(--color-tip);
}

.markdown-alert.markdown-alert-caution {
  border-left-color: var(--color-caution);
}

.markdown-alert.markdown-alert-caution .markdown-alert-title {
  color: var(--color-caution);
}

</style>
        
        </head>
        <body class="vscode-body vscode-light">
            <h1 id="作品模块功能需求文档">作品模块功能需求文档</h1>
<p><strong>版本：</strong> v2.0.0<br>
<strong>更新时间：</strong> 2024-12-29<br>
<strong>技术架构：</strong> 基于若依(RuoYi)框架二次开发<br>
<strong>模块描述：</strong> 作品管理模块，支持书法作品的分步骤批量上传、多压缩格式支持、腾讯云COS存储、分类管理、标签管理、获奖等级管理和展示功能，仅使用GET和POST请求方法，包含完善的并发控制、进度监控和批量回滚机制</p>
<h2 id="技术架构说明">技术架构说明</h2>
<h3 id="若依框架集成">若依框架集成</h3>
<ul>
<li><strong>基础框架</strong>：RuoYi-Vue 分离版</li>
<li><strong>后端技术栈</strong>：Spring Boot + MyBatis-Plus + Redis + MySQL + 腾讯云COS</li>
<li><strong>前端技术栈</strong>：Vue.js + Element UI + WebSocket</li>
<li><strong>权限管理</strong>：集成若依权限系统，支持角色和菜单权限控制</li>
<li><strong>数据验证</strong>：使用若依统一的参数校验机制</li>
<li><strong>异常处理</strong>：遵循若依统一异常处理规范</li>
<li><strong>日志记录</strong>：集成若依操作日志系统</li>
<li><strong>文件上传</strong>：基于若依文件上传组件扩展，支持腾讯云COS存储</li>
<li><strong>压缩格式支持</strong>：ZIP、RAR、7Z等多种压缩格式</li>
<li><strong>并发控制</strong>：基于Redis的分布式锁和任务队列</li>
<li><strong>进度监控</strong>：WebSocket实时进度推送</li>
<li><strong>批量回滚</strong>：支持一键回滚批次上传操作</li>
</ul>
<h3 id="模块结构">模块结构</h3>
<p><strong>模块位置：</strong> <code>/d:/A_prj/shufa_release2/shufa-ht/shufa-admin/</code></p>
<pre><code>com.shufa.works/
├── controller/          # 控制器层
│   ├── WorksController.java
│   ├── WorksAppController.java
│   ├── WorksCategoryController.java
│   ├── WorksTagController.java
│   ├── WorksAwardController.java
│   └── WorksBatchUploadController.java  # 分步骤上传控制器
├── service/            # 服务层
│   ├── IWorksService.java
│   ├── IWorksCategoryService.java
│   ├── IWorksTagService.java
│   ├── IWorksAwardService.java
│   ├── IWorksBatchUploadService.java    # 批量上传服务
│   ├── IWorksRollbackService.java       # 回滚服务
│   └── impl/
│       ├── WorksServiceImpl.java
│       ├── WorksCategoryServiceImpl.java
│       ├── WorksTagServiceImpl.java
│       ├── WorksAwardServiceImpl.java
│       ├── WorksBatchUploadServiceImpl.java
│       └── WorksRollbackServiceImpl.java
├── mapper/             # 数据访问层
│   ├── WorksMapper.java
│   ├── WorksCategoryMapper.java
│   ├── WorksTagMapper.java
│   ├── WorksAwardMapper.java
│   ├── WorksImageMapper.java
│   └── WorksBatchUploadMapper.java      # 批次上传记录
├── domain/             # 实体类
│   ├── Works.java
│   ├── WorksCategory.java
│   ├── WorksTag.java
│   ├── WorksAward.java
│   ├── WorksImage.java
│   └── WorksBatchUpload.java            # 批次上传记录
├── vo/                 # 视图对象
│   ├── WorksVO.java
│   ├── WorksAppVO.java
│   ├── WorksUploadVO.java
│   ├── WorksBatchUploadVO.java
│   ├── WorksUploadProgressVO.java       # 上传进度
│   └── WorksRollbackVO.java             # 回滚信息
├── utils/              # 工具类
│   ├── CompressUtil.java                # 压缩包处理工具
│   ├── CosUploadUtil.java               # 腾讯云COS上传工具
│   ├── ProgressWebSocketHandler.java    # WebSocket进度推送
│   └── ConcurrencyControlUtil.java      # 并发控制工具
└── task/               # 定时任务
    ├── WorksCleanTask.java
    └── WorksUploadTimeoutTask.java      # 上传超时清理任务
</code></pre>
<h2 id="接口概览">接口概览</h2>
<table>
<thead>
<tr>
<th>接口名称</th>
<th>请求方法</th>
<th>URL</th>
<th>功能描述</th>
<th>权限要求</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>作品标签管理</strong></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>创建作品标签</td>
<td>POST</td>
<td>/api/v1/admin/works/tags</td>
<td>创建新的作品标签</td>
<td>管理员</td>
</tr>
<tr>
<td>更新作品标签</td>
<td>POST</td>
<td>/api/v1/admin/works/tags/update</td>
<td>更新作品标签信息</td>
<td>管理员</td>
</tr>
<tr>
<td>删除作品标签</td>
<td>POST</td>
<td>/api/v1/admin/works/tags/remove</td>
<td>删除作品标签</td>
<td>管理员</td>
</tr>
<tr>
<td>获取作品标签列表</td>
<td>GET</td>
<td>/api/v1/admin/works/tags</td>
<td>获取作品标签列表</td>
<td>管理员</td>
</tr>
<tr>
<td><strong>作品分类管理</strong></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>创建作品分类</td>
<td>POST</td>
<td>/api/v1/admin/works/categories</td>
<td>创建新的作品分类</td>
<td>管理员</td>
</tr>
<tr>
<td>更新作品分类</td>
<td>POST</td>
<td>/api/v1/admin/works/categories/update</td>
<td>更新作品分类信息</td>
<td>管理员</td>
</tr>
<tr>
<td>删除作品分类</td>
<td>POST</td>
<td>/api/v1/admin/works/categories/remove</td>
<td>删除作品分类</td>
<td>管理员</td>
</tr>
<tr>
<td>获取作品分类列表</td>
<td>GET</td>
<td>/api/v1/admin/works/categories</td>
<td>获取作品分类列表</td>
<td>管理员</td>
</tr>
<tr>
<td><strong>作品获奖等级管理</strong></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>创建获奖等级</td>
<td>POST</td>
<td>/api/v1/admin/works/awards</td>
<td>创建新的获奖等级</td>
<td>管理员</td>
</tr>
<tr>
<td>更新获奖等级</td>
<td>POST</td>
<td>/api/v1/admin/works/awards/update</td>
<td>更新获奖等级信息</td>
<td>管理员</td>
</tr>
<tr>
<td>删除获奖等级</td>
<td>POST</td>
<td>/api/v1/admin/works/awards/remove</td>
<td>删除获奖等级</td>
<td>管理员</td>
</tr>
<tr>
<td>获取获奖等级列表</td>
<td>GET</td>
<td>/api/v1/admin/works/awards</td>
<td>获取获奖等级列表</td>
<td>管理员</td>
</tr>
<tr>
<td><strong>作品管理</strong></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>获取作品列表(管理后台)</td>
<td>GET</td>
<td>/api/v1/admin/works</td>
<td>管理后台获取作品列表</td>
<td>管理员</td>
</tr>
<tr>
<td>获取作品详情(管理后台)</td>
<td>GET</td>
<td>/api/v1/admin/works/{id}</td>
<td>管理后台获取作品详情</td>
<td>管理员</td>
</tr>
<tr>
<td>更新作品信息</td>
<td>POST</td>
<td>/api/v1/admin/works/update</td>
<td>更新作品信息</td>
<td>管理员</td>
</tr>
<tr>
<td>删除作品</td>
<td>POST</td>
<td>/api/v1/admin/works/remove</td>
<td>删除作品</td>
<td>管理员</td>
</tr>
<tr>
<td>添加作品图片</td>
<td>POST</td>
<td>/api/v1/admin/works/{id}/images</td>
<td>为作品添加图片</td>
<td>管理员</td>
</tr>
<tr>
<td>删除作品图片</td>
<td>POST</td>
<td>/api/v1/admin/works/images/remove</td>
<td>删除作品图片</td>
<td>管理员</td>
</tr>
<tr>
<td>更新作品获奖等级</td>
<td>POST</td>
<td>/api/v1/admin/works/{id}/award</td>
<td>更新作品获奖等级</td>
<td>管理员</td>
</tr>
<tr>
<td>添加作品评语</td>
<td>POST</td>
<td>/api/v1/admin/works/{id}/comment</td>
<td>添加作品评语</td>
<td>管理员</td>
</tr>
<tr>
<td><strong>分步骤批量上传</strong></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>步骤1：上传压缩包</td>
<td>POST</td>
<td>/api/v1/admin/works/upload/step1</td>
<td>上传并验证压缩包格式</td>
<td>管理员</td>
</tr>
<tr>
<td>步骤2：解析并上传COS</td>
<td>POST</td>
<td>/api/v1/admin/works/upload/step2</td>
<td>解析压缩包并上传图片到COS</td>
<td>管理员</td>
</tr>
<tr>
<td>步骤3：确认导入配置</td>
<td>POST</td>
<td>/api/v1/admin/works/upload/step3</td>
<td>确认导入配置并执行数据库插入</td>
<td>管理员</td>
</tr>
<tr>
<td>获取上传进度</td>
<td>GET</td>
<td>/api/v1/admin/works/upload/progress/{uploadId}</td>
<td>获取上传任务进度</td>
<td>管理员</td>
</tr>
<tr>
<td>取消上传任务</td>
<td>POST</td>
<td>/api/v1/admin/works/upload/cancel</td>
<td>取消正在进行的上传任务</td>
<td>管理员</td>
</tr>
<tr>
<td><strong>批量回滚管理</strong></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>获取批次列表</td>
<td>GET</td>
<td>/api/v1/admin/works/batches</td>
<td>获取批次上传记录列表</td>
<td>管理员</td>
</tr>
<tr>
<td>批量回滚</td>
<td>POST</td>
<td>/api/v1/admin/works/rollback</td>
<td>回滚指定批次的所有数据</td>
<td>管理员</td>
</tr>
<tr>
<td><strong>App端接口</strong></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>获取首页作品列表</td>
<td>GET</td>
<td>/api/v1/works/homepage</td>
<td>App端获取首页作品列表</td>
<td>无</td>
</tr>
<tr>
<td>获取优秀作品列表</td>
<td>GET</td>
<td>/api/v1/works/excellent</td>
<td>App端获取优秀作品列表</td>
<td>无</td>
</tr>
<tr>
<td>获取作品详情(App端)</td>
<td>GET</td>
<td>/api/v1/works/{id}</td>
<td>App端获取作品详情</td>
<td>无</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="1-作品标签管理">1. 作品标签管理</h2>
<h3 id="11-创建作品标签">1.1 创建作品标签</h3>
<h4 id="基本信息">基本信息</h4>
<ul>
<li><strong>功能：</strong> 管理员创建新的作品标签</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/tags</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多20次</li>
</ul>
<h4 id="请求参数">请求参数</h4>
<h5 id="请求头">请求头</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>Authorization</td>
<td>String</td>
<td>是</td>
<td>Bearer Token</td>
<td>Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...</td>
</tr>
</tbody>
</table>
<h5 id="请求体参数">请求体参数</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;tagName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;首页&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;tagDescription&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;首页展示的作品&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;sortOrder&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;isEnabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>tagName</td>
<td>String</td>
<td>是</td>
<td>标签名称(1-20字符)</td>
<td>首页</td>
</tr>
<tr>
<td>tagDescription</td>
<td>String</td>
<td>否</td>
<td>标签描述(最多100字符)</td>
<td>首页展示的作品</td>
</tr>
<tr>
<td>sortOrder</td>
<td>Integer</td>
<td>否</td>
<td>排序顺序</td>
<td>1</td>
</tr>
<tr>
<td>isEnabled</td>
<td>Boolean</td>
<td>否</td>
<td>是否启用</td>
<td>true</td>
</tr>
</tbody>
</table>
<h4 id="返回参数">返回参数</h4>
<h5 id="成功响应">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;作品标签创建成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;tagId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;tagName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;首页&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;tagDescription&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;首页展示的作品&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;sortOrder&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;isEnabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;createTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 10:30:00&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h3 id="12-获取作品标签列表">1.2 获取作品标签列表</h3>
<h4 id="基本信息-1">基本信息</h4>
<ul>
<li><strong>功能：</strong> 获取作品标签列表</li>
<li><strong>接口地址：</strong> <code>GET /api/v1/admin/works/tags</code></li>
<li><strong>请求方式：</strong> GET</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多100次</li>
</ul>
<h4 id="请求参数-1">请求参数</h4>
<h5 id="查询参数">查询参数</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>默认值</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>tagName</td>
<td>String</td>
<td>否</td>
<td>标签名称关键词搜索</td>
<td>-</td>
<td>首页</td>
</tr>
<tr>
<td>isEnabled</td>
<td>Boolean</td>
<td>否</td>
<td>是否启用状态筛选</td>
<td>-</td>
<td>true</td>
</tr>
<tr>
<td>pageNum</td>
<td>Integer</td>
<td>否</td>
<td>页码</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>pageSize</td>
<td>Integer</td>
<td>否</td>
<td>每页数量</td>
<td>20</td>
<td>20</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-1">返回参数</h4>
<h5 id="成功响应-1">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;操作成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;total&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">2</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;list&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;tagId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">0</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;tagName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;首页&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;tagDescription&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;首页展示的作品&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;sortOrder&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;isEnabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;createTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 10:30:00&quot;</span>
      <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;tagId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;tagName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;优秀作品&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;tagDescription&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;优秀作品展示&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;sortOrder&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">2</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;isEnabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;createTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 10:31:00&quot;</span>
      <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<hr>
<h2 id="2-作品分类管理">2. 作品分类管理</h2>
<h3 id="21-创建作品分类">2.1 创建作品分类</h3>
<h4 id="基本信息-2">基本信息</h4>
<ul>
<li><strong>功能：</strong> 管理员创建新的作品分类</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/categories</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多20次</li>
</ul>
<h4 id="请求参数-2">请求参数</h4>
<h5 id="请求体参数-1">请求体参数</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;categoryName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;书法&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;categoryDescription&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;书法作品分类&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;sortOrder&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;isEnabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>categoryName</td>
<td>String</td>
<td>是</td>
<td>分类名称(1-20字符)</td>
<td>书法</td>
</tr>
<tr>
<td>categoryDescription</td>
<td>String</td>
<td>否</td>
<td>分类描述(最多100字符)</td>
<td>书法作品分类</td>
</tr>
<tr>
<td>sortOrder</td>
<td>Integer</td>
<td>否</td>
<td>排序顺序</td>
<td>1</td>
</tr>
<tr>
<td>isEnabled</td>
<td>Boolean</td>
<td>否</td>
<td>是否启用</td>
<td>true</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-2">返回参数</h4>
<h5 id="成功响应-2">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;作品分类创建成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;categoryId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;categoryName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;书法&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;categoryDescription&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;书法作品分类&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;sortOrder&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;isEnabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;createTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 10:30:00&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h3 id="22-删除作品分类">2.2 删除作品分类</h3>
<h4 id="基本信息-3">基本信息</h4>
<ul>
<li><strong>功能：</strong> 管理员删除作品分类</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/categories/remove</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多10次</li>
</ul>
<h4 id="请求参数-3">请求参数</h4>
<h5 id="请求体参数-2">请求体参数</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;categoryId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>categoryId</td>
<td>Long</td>
<td>是</td>
<td>分类ID</td>
<td>1</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-3">返回参数</h4>
<h5 id="成功响应-3">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;作品分类删除成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">null</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h5 id="错误响应">错误响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">5003</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">false</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;该类别已有作品引用，无法删除&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">null</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<p><strong>注意：</strong> 删除分类前会检查是否有作品引用该分类，如有引用则不允许删除。</p>
<hr>
<h2 id="3-作品获奖等级管理">3. 作品获奖等级管理</h2>
<h3 id="31-创建获奖等级">3.1 创建获奖等级</h3>
<h4 id="基本信息-4">基本信息</h4>
<ul>
<li><strong>功能：</strong> 管理员创建新的获奖等级</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/awards</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多20次</li>
</ul>
<h4 id="请求参数-4">请求参数</h4>
<h5 id="请求体参数-3">请求体参数</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;awardName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;特等奖&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;awardDescription&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;最高等级奖项&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;awardLevel&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;sortOrder&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;isEnabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>awardName</td>
<td>String</td>
<td>是</td>
<td>获奖等级名称(1-20字符)</td>
<td>特等奖</td>
</tr>
<tr>
<td>awardDescription</td>
<td>String</td>
<td>否</td>
<td>获奖等级描述(最多100字符)</td>
<td>最高等级奖项</td>
</tr>
<tr>
<td>awardLevel</td>
<td>Integer</td>
<td>是</td>
<td>奖项等级(1-10)</td>
<td>1</td>
</tr>
<tr>
<td>sortOrder</td>
<td>Integer</td>
<td>否</td>
<td>排序顺序</td>
<td>1</td>
</tr>
<tr>
<td>isEnabled</td>
<td>Boolean</td>
<td>否</td>
<td>是否启用</td>
<td>true</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-4">返回参数</h4>
<h5 id="成功响应-4">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;获奖等级创建成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;awardId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;awardName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;特等奖&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;awardDescription&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;最高等级奖项&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;awardLevel&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;sortOrder&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;isEnabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;createTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 10:30:00&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<hr>
<h2 id="4-作品管理">4. 作品管理</h2>
<h3 id="41-分步骤批量上传作品">4.1 分步骤批量上传作品</h3>
<h4 id="概述">概述</h4>
<p>分步骤批量上传采用三步骤流程，支持多种压缩格式，图片上传至腾讯云COS，具备完善的进度监控和并发控制机制。</p>
<p><strong>支持的压缩格式：</strong> ZIP、RAR、7Z<br>
<strong>并发限制：</strong> 普通用户同时只能有1个上传任务，管理员最多3个<br>
<strong>超时限制：</strong> 单个上传任务最长1小时<br>
<strong>文件清理：</strong> 临时文件7天后自动清理</p>
<h4 id="411-步骤1上传压缩包">4.1.1 步骤1：上传压缩包</h4>
<h5 id="基本信息-5">基本信息</h5>
<ul>
<li><strong>功能：</strong> 上传压缩包并进行格式验证</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/upload/step1</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多5次</li>
<li><strong>并发控制：</strong> 基于Redis分布式锁，用户级别限制</li>
</ul>
<h5 id="请求参数-5">请求参数</h5>
<h6 id="请求头-1">请求头</h6>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>Authorization</td>
<td>String</td>
<td>是</td>
<td>Bearer Token</td>
<td>Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...</td>
</tr>
<tr>
<td>Content-Type</td>
<td>String</td>
<td>是</td>
<td>内容类型</td>
<td>multipart/form-data</td>
</tr>
</tbody>
</table>
<h6 id="表单参数">表单参数</h6>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>file</td>
<td>File</td>
<td>是</td>
<td>作品压缩包文件(最大1GB，支持ZIP/RAR/7Z)</td>
<td>works.zip</td>
</tr>
<tr>
<td>competitionId</td>
<td>Long</td>
<td>是</td>
<td>关联的比赛活动ID</td>
<td>1001</td>
</tr>
<tr>
<td>defaultTagIds</td>
<td>String</td>
<td>否</td>
<td>默认标签ID列表(逗号分隔)</td>
<td>0,1</td>
</tr>
</tbody>
</table>
<h6 id="压缩包目录结构要求">压缩包目录结构要求</h6>
<pre><code class="language-plaintext">压缩包根目录/
  ├──书法/
  │    ├──张三@海阔天空/
  |    |       ├──海阔天空1.jpg
  |    |       ├──海阔续篇2.jpg
  |    |       └──我爱你.jpg
  │    └──李四@天道酬勤/
  |            ├──天道酬勤1.jpg
  |            ├──海阔续篇2.jpg
  |            └──海天.jpg
  ├──国画/
  |    ├──王五@猛虎下山图/
  |            ├──猛虎下山1.jpg
  |            ├──猛虎下山2.jpg
  |            └──猛虎n.jpg
  |    └──王八@清明上河图/
  |            ├──xxx1.jpg
  |            ├──xxx2.jpg
  |            └──xxx3.jpg
</code></pre>
<p><strong>目录结构说明：</strong></p>
<ol>
<li>一级文件夹名字（如&quot;书法&quot;、&quot;国画&quot;）是作品的分类</li>
<li>二级文件夹格式为&quot;作者@作品标题&quot;（如&quot;张三@海阔天空&quot;）</li>
<li>二级文件夹下的图片是作品图片</li>
</ol>
<h5 id="返回参数-5">返回参数</h5>
<h6 id="成功响应-5">成功响应</h6>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;压缩包上传成功，格式验证通过&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;uploadId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;upload_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;fileName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;works.zip&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;fileSize&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">524288000</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;compressFormat&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;ZIP&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;tempFilePath&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;/temp/upload_20241229_103000/works.zip&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;competitionId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;defaultTagIds&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-number">0</span><span class="hljs-punctuation">,</span> <span class="hljs-number">1</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;status&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;UPLOADED&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;createTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-12-29 10:30:00&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;expireTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2025-01-05 10:30:00&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h4 id="412-步骤2解析并上传到腾讯云cos">4.1.2 步骤2：解析并上传到腾讯云COS</h4>
<h5 id="基本信息-6">基本信息</h5>
<ul>
<li><strong>功能：</strong> 解析压缩包并将图片上传到腾讯云COS</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/upload/step2</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多10次</li>
<li><strong>进度监控：</strong> 支持WebSocket实时进度推送</li>
</ul>
<h5 id="请求参数-6">请求参数</h5>
<h6 id="请求体参数-4">请求体参数</h6>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;uploadId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;upload_20241229_103000&quot;</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>uploadId</td>
<td>String</td>
<td>是</td>
<td>步骤1返回的上传ID</td>
<td>upload_20241229_103000</td>
</tr>
</tbody>
</table>
<h5 id="返回参数-6">返回参数</h5>
<h6 id="成功响应-6">成功响应</h6>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;开始解析压缩包并上传到COS&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;uploadId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;upload_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;status&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;PROCESSING&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;totalFiles&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">12</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;processedFiles&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">0</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;progress&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">0</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;websocketUrl&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;ws://localhost:8080/ws/upload/progress/upload_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;estimatedTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;预计需要5-10分钟&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;startTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-12-29 10:35:00&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h4 id="413-步骤3确认导入配置">4.1.3 步骤3：确认导入配置</h4>
<h5 id="基本信息-7">基本信息</h5>
<ul>
<li><strong>功能：</strong> 确认导入配置并执行数据库插入</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/upload/step3</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多10次</li>
</ul>
<h5 id="请求参数-7">请求参数</h5>
<h6 id="请求体参数-5">请求体参数</h6>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;uploadId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;upload_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;confirmImport&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;batchName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024年度书画作品第一批&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;importConfig&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;autoCreateCategory&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;defaultAwardId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">6</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;overwriteExisting&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">false</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>uploadId</td>
<td>String</td>
<td>是</td>
<td>上传任务ID</td>
<td>upload_20241229_103000</td>
</tr>
<tr>
<td>confirmImport</td>
<td>Boolean</td>
<td>是</td>
<td>确认导入</td>
<td>true</td>
</tr>
<tr>
<td>batchName</td>
<td>String</td>
<td>否</td>
<td>批次名称</td>
<td>2024年度书画作品第一批</td>
</tr>
<tr>
<td>importConfig</td>
<td>Object</td>
<td>否</td>
<td>导入配置</td>
<td>-</td>
</tr>
<tr>
<td>importConfig.autoCreateCategory</td>
<td>Boolean</td>
<td>否</td>
<td>自动创建分类</td>
<td>true</td>
</tr>
<tr>
<td>importConfig.defaultAwardId</td>
<td>Long</td>
<td>否</td>
<td>默认获奖等级ID</td>
<td>6</td>
</tr>
<tr>
<td>importConfig.overwriteExisting</td>
<td>Boolean</td>
<td>否</td>
<td>覆盖已存在作品</td>
<td>false</td>
</tr>
</tbody>
</table>
<h5 id="返回参数-7">返回参数</h5>
<h6 id="成功响应-7">成功响应</h6>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;作品数据导入成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;uploadId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;upload_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;batchId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;batch_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;batchName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024年度书画作品第一批&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;totalWorks&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">4</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;successCount&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">4</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;failCount&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">0</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;newCategories&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">&quot;书法&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-string">&quot;国画&quot;</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;importTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-12-29 10:45:00&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;works&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;worksId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;title&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;海阔天空&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;author&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;张三&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;categoryName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;书法&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;imageCount&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">3</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;cosUrls&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
          <span class="hljs-string">&quot;https://cos.example.com/works/1001/image1.jpg&quot;</span><span class="hljs-punctuation">,</span>
          <span class="hljs-string">&quot;https://cos.example.com/works/1001/image2.jpg&quot;</span><span class="hljs-punctuation">,</span>
          <span class="hljs-string">&quot;https://cos.example.com/works/1001/image3.jpg&quot;</span>
        <span class="hljs-punctuation">]</span>
      <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h3 id="42-获取上传进度">4.2 获取上传进度</h3>
<h4 id="基本信息-8">基本信息</h4>
<ul>
<li><strong>功能：</strong> 获取上传任务的实时进度</li>
<li><strong>接口地址：</strong> <code>GET /api/v1/admin/works/upload/progress/{uploadId}</code></li>
<li><strong>请求方式：</strong> GET</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多60次</li>
</ul>
<h4 id="请求参数-8">请求参数</h4>
<h5 id="路径参数">路径参数</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>uploadId</td>
<td>String</td>
<td>是</td>
<td>上传任务ID</td>
<td>upload_20241229_103000</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-8">返回参数</h4>
<h5 id="成功响应-8">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;操作成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;uploadId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;upload_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;status&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;PROCESSING&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;currentStep&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">2</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;totalSteps&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">3</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;progress&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">65</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;totalFiles&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">12</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;processedFiles&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">8</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;currentFile&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;张三@海阔天空/海阔天空3.jpg&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;startTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-12-29 10:35:00&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;estimatedRemaining&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;预计还需2分钟&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;errorCount&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">0</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;errors&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-punctuation">]</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h3 id="43-取消上传任务">4.3 取消上传任务</h3>
<h4 id="基本信息-9">基本信息</h4>
<ul>
<li><strong>功能：</strong> 取消正在进行的上传任务</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/upload/cancel</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多10次</li>
</ul>
<h4 id="请求参数-9">请求参数</h4>
<h5 id="请求体参数-6">请求体参数</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;uploadId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;upload_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;reason&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;用户主动取消&quot;</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>uploadId</td>
<td>String</td>
<td>是</td>
<td>上传任务ID</td>
<td>upload_20241229_103000</td>
</tr>
<tr>
<td>reason</td>
<td>String</td>
<td>否</td>
<td>取消原因</td>
<td>用户主动取消</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-9">返回参数</h4>
<h5 id="成功响应-9">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;上传任务已取消&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;uploadId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;upload_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;status&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;CANCELLED&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;cancelTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-12-29 10:40:00&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;reason&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;用户主动取消&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;cleanupStatus&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;已清理临时文件&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h2 id="5-批量回滚管理">5. 批量回滚管理</h2>
<h3 id="51-获取批次列表">5.1 获取批次列表</h3>
<h4 id="基本信息-10">基本信息</h4>
<ul>
<li><strong>功能：</strong> 获取批次上传记录列表</li>
<li><strong>接口地址：</strong> <code>GET /api/v1/admin/works/batches</code></li>
<li><strong>请求方式：</strong> GET</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多100次</li>
</ul>
<h4 id="请求参数-10">请求参数</h4>
<h5 id="查询参数-1">查询参数</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>默认值</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>competitionId</td>
<td>Long</td>
<td>否</td>
<td>比赛活动ID</td>
<td>-</td>
<td>1001</td>
</tr>
<tr>
<td>batchName</td>
<td>String</td>
<td>否</td>
<td>批次名称关键词搜索</td>
<td>-</td>
<td>2024年度</td>
</tr>
<tr>
<td>status</td>
<td>String</td>
<td>否</td>
<td>批次状态(COMPLETED/ROLLBACKED)</td>
<td>-</td>
<td>COMPLETED</td>
</tr>
<tr>
<td>startDate</td>
<td>String</td>
<td>否</td>
<td>开始日期(YYYY-MM-DD)</td>
<td>-</td>
<td>2024-12-01</td>
</tr>
<tr>
<td>endDate</td>
<td>String</td>
<td>否</td>
<td>结束日期(YYYY-MM-DD)</td>
<td>-</td>
<td>2024-12-31</td>
</tr>
<tr>
<td>pageNum</td>
<td>Integer</td>
<td>否</td>
<td>页码</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>pageSize</td>
<td>Integer</td>
<td>否</td>
<td>每页数量</td>
<td>20</td>
<td>20</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-10">返回参数</h4>
<h5 id="成功响应-10">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;操作成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;total&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">5</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;list&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;batchId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;batch_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;batchName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024年度书画作品第一批&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;uploadId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;upload_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;competitionId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;competitionTitle&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2025韶华墨韵书画艺术大赛&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;totalWorks&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">4</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;totalImages&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">12</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;status&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;COMPLETED&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;createTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-12-29 10:45:00&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;createBy&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;admin&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;rollbackTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">null</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;rollbackBy&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">null</span>
      <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h3 id="52-批量回滚">5.2 批量回滚</h3>
<h4 id="基本信息-11">基本信息</h4>
<ul>
<li><strong>功能：</strong> 回滚指定批次的所有数据</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/rollback</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多5次</li>
<li><strong>操作范围：</strong> 删除数据库记录、删除COS文件、清理缓存</li>
</ul>
<h4 id="请求参数-11">请求参数</h4>
<h5 id="请求体参数-7">请求体参数</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;batchId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;batch_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;reason&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;数据错误，需要重新导入&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;confirmRollback&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>batchId</td>
<td>String</td>
<td>是</td>
<td>批次ID</td>
<td>batch_20241229_103000</td>
</tr>
<tr>
<td>reason</td>
<td>String</td>
<td>是</td>
<td>回滚原因</td>
<td>数据错误，需要重新导入</td>
</tr>
<tr>
<td>confirmRollback</td>
<td>Boolean</td>
<td>是</td>
<td>确认回滚操作</td>
<td>true</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-11">返回参数</h4>
<h5 id="成功响应-11">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;批次回滚成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;batchId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;batch_20241229_103000&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;rollbackTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-12-29 15:30:00&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;rollbackBy&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;admin&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;deletedWorks&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">4</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;deletedImages&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">12</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;deletedCosFiles&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">12</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;clearedCacheKeys&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">8</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;reason&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;数据错误，需要重新导入&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;rollbackDetails&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
      <span class="hljs-attr">&quot;worksIds&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-number">1001</span><span class="hljs-punctuation">,</span> <span class="hljs-number">1002</span><span class="hljs-punctuation">,</span> <span class="hljs-number">1003</span><span class="hljs-punctuation">,</span> <span class="hljs-number">1004</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
      <span class="hljs-attr">&quot;cosUrls&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
        <span class="hljs-string">&quot;https://cos.example.com/works/1001/image1.jpg&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-string">&quot;https://cos.example.com/works/1001/image2.jpg&quot;</span>
      <span class="hljs-punctuation">]</span>
    <span class="hljs-punctuation">}</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<hr>
<h2 id="6-作品管理">6. 作品管理</h2>
<h3 id="61-获取作品列表管理后台">6.1 获取作品列表(管理后台)</h3>
<h4 id="基本信息-12">基本信息</h4>
<ul>
<li><strong>功能：</strong> 管理后台获取作品列表</li>
<li><strong>接口地址：</strong> <code>GET /api/v1/admin/works</code></li>
<li><strong>请求方式：</strong> GET</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多100次</li>
</ul>
<h4 id="请求参数-12">请求参数</h4>
<h5 id="查询参数-2">查询参数</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>默认值</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>competitionId</td>
<td>Long</td>
<td>否</td>
<td>比赛活动ID</td>
<td>-</td>
<td>1001</td>
</tr>
<tr>
<td>categoryId</td>
<td>Long</td>
<td>否</td>
<td>分类ID</td>
<td>-</td>
<td>1</td>
</tr>
<tr>
<td>tagId</td>
<td>Long</td>
<td>否</td>
<td>标签ID</td>
<td>-</td>
<td>0</td>
</tr>
<tr>
<td>awardId</td>
<td>Long</td>
<td>否</td>
<td>获奖等级ID</td>
<td>-</td>
<td>1</td>
</tr>
<tr>
<td>author</td>
<td>String</td>
<td>否</td>
<td>作者名称关键词搜索</td>
<td>-</td>
<td>张三</td>
</tr>
<tr>
<td>title</td>
<td>String</td>
<td>否</td>
<td>作品标题关键词搜索</td>
<td>-</td>
<td>海阔天空</td>
</tr>
<tr>
<td>pageNum</td>
<td>Integer</td>
<td>否</td>
<td>页码</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>pageSize</td>
<td>Integer</td>
<td>否</td>
<td>每页数量</td>
<td>20</td>
<td>20</td>
</tr>
<tr>
<td>sortBy</td>
<td>String</td>
<td>否</td>
<td>排序方式(createTime/title/author)</td>
<td>createTime</td>
<td>createTime</td>
</tr>
<tr>
<td>sortOrder</td>
<td>String</td>
<td>否</td>
<td>排序顺序(asc/desc)</td>
<td>desc</td>
<td>desc</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-12">返回参数</h4>
<h5 id="成功响应-12">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;操作成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;total&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">10</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;list&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;worksId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;title&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;海阔天空&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;author&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;张三&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;competitionId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;competitionTitle&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2025韶华墨韵书画艺术大赛&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;categoryId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;categoryName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;书法&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;awardId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">6</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;awardName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;未获奖&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;tagIds&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-number">0</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;tagNames&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">&quot;首页&quot;</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;imageCount&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">3</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;thumbnailUrl&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://your-bucket.cos.ap-beijing.myqcloud.com/works/thumbnails/1001_thumb.jpg&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;comment&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">null</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;commentDisplayLength&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">0</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;createTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 10:30:00&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;updateTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 10:30:00&quot;</span>
      <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h3 id="43-获取作品详情管理后台">4.3 获取作品详情(管理后台)</h3>
<h4 id="基本信息-13">基本信息</h4>
<ul>
<li><strong>功能：</strong> 管理后台获取作品详情</li>
<li><strong>接口地址：</strong> <code>GET /api/v1/admin/works/{id}</code></li>
<li><strong>请求方式：</strong> GET</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多100次</li>
</ul>
<h4 id="请求参数-13">请求参数</h4>
<h5 id="路径参数-1">路径参数</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>Long</td>
<td>是</td>
<td>作品ID</td>
<td>1001</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-13">返回参数</h4>
<h5 id="成功响应-13">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;操作成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;worksId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;title&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;海阔天空&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;author&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;张三&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;competitionId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;competitionTitle&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2025韶华墨韵书画艺术大赛&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;categoryId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;categoryName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;书法&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;awardId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">6</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;awardName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;未获奖&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;tagIds&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-number">0</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;tagNames&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">&quot;首页&quot;</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;comment&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;这是一幅优秀的书法作品&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;commentDisplayLength&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">50</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;images&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;imageId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;imageUrl&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://your-bucket.cos.ap-beijing.myqcloud.com/works/images/1001/海阔天空1_20240115103000.jpg&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;thumbnailUrl&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://your-bucket.cos.ap-beijing.myqcloud.com/works/thumbnails/1001/海阔天空1_20240115103000_thumb.jpg&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;originalName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;海阔天空1.jpg&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;fileSize&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1024000</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;sortOrder&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;uploadTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 10:30:00&quot;</span>
      <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;createTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 10:30:00&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;updateTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 10:30:00&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h3 id="44-更新作品获奖等级">4.4 更新作品获奖等级</h3>
<h4 id="基本信息-14">基本信息</h4>
<ul>
<li><strong>功能：</strong> 管理员更新作品获奖等级</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/{id}/award</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多50次</li>
</ul>
<h4 id="请求参数-14">请求参数</h4>
<h5 id="路径参数-2">路径参数</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>Long</td>
<td>是</td>
<td>作品ID</td>
<td>1001</td>
</tr>
</tbody>
</table>
<h5 id="请求体参数-8">请求体参数</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;awardId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>awardId</td>
<td>Long</td>
<td>是</td>
<td>获奖等级ID</td>
<td>1</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-14">返回参数</h4>
<h5 id="成功响应-14">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;作品获奖等级更新成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;worksId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;awardId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;awardName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;特等奖&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;updateTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 11:30:00&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h3 id="45-添加作品评语">4.5 添加作品评语</h3>
<h4 id="基本信息-15">基本信息</h4>
<ul>
<li><strong>功能：</strong> 管理员为作品添加评语</li>
<li><strong>接口地址：</strong> <code>POST /api/v1/admin/works/{id}/comment</code></li>
<li><strong>请求方式：</strong> POST</li>
<li><strong>权限要求：</strong> 管理员权限</li>
<li><strong>频率限制：</strong> 每分钟最多50次</li>
</ul>
<h4 id="请求参数-15">请求参数</h4>
<h5 id="路径参数-3">路径参数</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>Long</td>
<td>是</td>
<td>作品ID</td>
<td>1001</td>
</tr>
</tbody>
</table>
<h5 id="请求体参数-9">请求体参数</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;comment&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;这是一幅优秀的书法作品，笔法娴熟，意境深远。&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;displayLength&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">50</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>comment</td>
<td>String</td>
<td>是</td>
<td>评语内容(最多500字符)</td>
<td>这是一幅优秀的书法作品</td>
</tr>
<tr>
<td>displayLength</td>
<td>Integer</td>
<td>否</td>
<td>展示字数限制</td>
<td>50</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-15">返回参数</h4>
<h5 id="成功响应-15">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-keyword">true</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;作品评语添加成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;worksId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;comment&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;这是一幅优秀的书法作品，笔法娴熟，意境深远。&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;displayLength&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">50</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;updateTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;2024-01-15 11:30:00&quot;</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<hr>
<h2 id="5-app端接口">5. App端接口</h2>
<h3 id="51-获取首页作品列表">5.1 获取首页作品列表</h3>
<h4 id="基本信息-16">基本信息</h4>
<ul>
<li><strong>功能：</strong> App端获取首页作品列表</li>
<li><strong>接口地址：</strong> <code>GET /api/v1/works/homepage</code></li>
<li><strong>请求方式：</strong> GET</li>
<li><strong>权限要求：</strong> 无需登录</li>
<li><strong>频率限制：</strong> 每分钟最多200次</li>
</ul>
<h4 id="请求参数-16">请求参数</h4>
<h5 id="查询参数-3">查询参数</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>默认值</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>pageNum</td>
<td>Integer</td>
<td>否</td>
<td>页码</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>pageSize</td>
<td>Integer</td>
<td>否</td>
<td>每页数量</td>
<td>20</td>
<td>20</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-16">返回参数</h4>
<h5 id="成功响应-16">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;操作成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;total&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">10</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;list&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;worksId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;title&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;海阔天空&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;author&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;张三&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;categoryName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;书法&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;awardName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;特等奖&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;thumbnailUrl&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://your-bucket.cos.ap-beijing.myqcloud.com/works/thumbnails/1001_thumb.jpg&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;imageCount&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">3</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;comment&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;这是一幅优秀的书法作品，笔法娴熟，意境深远。&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;displayComment&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;这是一幅优秀的书法作品，笔法娴熟，意境深远。&quot;</span>
      <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h3 id="52-获取优秀作品列表">5.2 获取优秀作品列表</h3>
<h4 id="基本信息-17">基本信息</h4>
<ul>
<li><strong>功能：</strong> App端获取优秀作品列表</li>
<li><strong>接口地址：</strong> <code>GET /api/v1/works/excellent</code></li>
<li><strong>请求方式：</strong> GET</li>
<li><strong>权限要求：</strong> 无需登录</li>
<li><strong>频率限制：</strong> 每分钟最多200次</li>
</ul>
<h4 id="请求参数-17">请求参数</h4>
<h5 id="查询参数-4">查询参数</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>默认值</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>pageNum</td>
<td>Integer</td>
<td>否</td>
<td>页码</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>pageSize</td>
<td>Integer</td>
<td>否</td>
<td>每页数量</td>
<td>20</td>
<td>20</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-17">返回参数</h4>
<h5 id="成功响应-17">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;操作成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;total&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">5</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;list&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;worksId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;title&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;海阔天空&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;author&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;张三&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;categoryName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;书法&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;awardName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;特等奖&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;thumbnailUrl&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://your-bucket.cos.ap-beijing.myqcloud.com/works/thumbnails/1001_thumb.jpg&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;imageCount&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">3</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;comment&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;这是一幅优秀的书法作品，笔法娴熟，意境深远。&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;displayComment&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;这是一幅优秀的书法作品，笔法娴熟，意境深远。&quot;</span>
      <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h3 id="53-获取作品详情app端">5.3 获取作品详情(App端)</h3>
<h4 id="基本信息-18">基本信息</h4>
<ul>
<li><strong>功能：</strong> App端获取作品详情</li>
<li><strong>接口地址：</strong> <code>GET /api/v1/works/{id}</code></li>
<li><strong>请求方式：</strong> GET</li>
<li><strong>权限要求：</strong> 无需登录</li>
<li><strong>频率限制：</strong> 每分钟最多200次</li>
</ul>
<h4 id="请求参数-18">请求参数</h4>
<h5 id="路径参数-4">路径参数</h5>
<table>
<thead>
<tr>
<th>参数名</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>Long</td>
<td>是</td>
<td>作品ID</td>
<td>1001</td>
</tr>
</tbody>
</table>
<h4 id="返回参数-18">返回参数</h4>
<h5 id="成功响应-18">成功响应</h5>
<pre><code class="language-json"><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">&quot;code&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;msg&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;操作成功&quot;</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">&quot;data&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;worksId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1001</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;title&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;海阔天空&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;author&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;张三&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;categoryName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;书法&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;awardName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;特等奖&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;comment&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;这是一幅优秀的书法作品，笔法娴熟，意境深远。&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;displayComment&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;这是一幅优秀的书法作品，笔法娴熟，意境深远。&quot;</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;images&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">&quot;imageUrl&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://your-bucket.cos.ap-beijing.myqcloud.com/works/images/1001/海阔天空1_20240115103000.jpg&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;thumbnailUrl&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;https://your-bucket.cos.ap-beijing.myqcloud.com/works/thumbnails/1001/海阔天空1_20240115103000_thumb.jpg&quot;</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">&quot;sortOrder&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span>
      <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<p><strong>注意：</strong></p>
<ul>
<li>App端只能访问当前活动的作品</li>
<li>App端不包含管理字段如createTime、updateTime等</li>
<li>图片URL返回腾讯云COS完整路径</li>
</ul>
<hr>
<h2 id="数据模型">数据模型</h2>
<h3 id="works-表">Works 表</h3>
<table>
<thead>
<tr>
<th>字段名</th>
<th>类型</th>
<th>长度</th>
<th>是否为空</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>works_id</td>
<td>BIGINT</td>
<td>-</td>
<td>NOT NULL</td>
<td>AUTO_INCREMENT</td>
<td>作品ID(主键)</td>
</tr>
<tr>
<td>title</td>
<td>VARCHAR</td>
<td>100</td>
<td>NOT NULL</td>
<td>-</td>
<td>作品标题</td>
</tr>
<tr>
<td>author</td>
<td>VARCHAR</td>
<td>50</td>
<td>NOT NULL</td>
<td>-</td>
<td>作者姓名</td>
</tr>
<tr>
<td>competition_id</td>
<td>BIGINT</td>
<td>-</td>
<td>NOT NULL</td>
<td>-</td>
<td>关联的比赛活动ID</td>
</tr>
<tr>
<td>category_id</td>
<td>BIGINT</td>
<td>-</td>
<td>NOT NULL</td>
<td>-</td>
<td>作品分类ID</td>
</tr>
<tr>
<td>award_id</td>
<td>BIGINT</td>
<td>-</td>
<td>NOT NULL</td>
<td>6</td>
<td>获奖等级ID(默认未获奖)</td>
</tr>
<tr>
<td>tag_ids</td>
<td>VARCHAR</td>
<td>200</td>
<td>NOT NULL</td>
<td>'0'</td>
<td>标签ID列表(逗号分隔)</td>
</tr>
<tr>
<td>comment</td>
<td>TEXT</td>
<td>-</td>
<td>NULL</td>
<td>-</td>
<td>作品评语</td>
</tr>
<tr>
<td>comment_display_length</td>
<td>INT</td>
<td>-</td>
<td>NOT NULL</td>
<td>0</td>
<td>评语展示字数</td>
</tr>
<tr>
<td>thumbnail_url</td>
<td>VARCHAR</td>
<td>500</td>
<td>NULL</td>
<td>-</td>
<td>缩略图URL</td>
</tr>
<tr>
<td>create_time</td>
<td>DATETIME</td>
<td>-</td>
<td>NOT NULL</td>
<td>CURRENT_TIMESTAMP</td>
<td>创建时间</td>
</tr>
<tr>
<td>update_time</td>
<td>DATETIME</td>
<td>-</td>
<td>NOT NULL</td>
<td>CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP</td>
<td>更新时间</td>
</tr>
<tr>
<td>create_by</td>
<td>VARCHAR</td>
<td>64</td>
<td>NULL</td>
<td>-</td>
<td>创建者</td>
</tr>
<tr>
<td>update_by</td>
<td>VARCHAR</td>
<td>64</td>
<td>NULL</td>
<td>-</td>
<td>更新者</td>
</tr>
<tr>
<td>is_author_awarded</td>
<td>TINYINT</td>
<td>1</td>
<td>NOT NULL</td>
<td>0</td>
<td>作者是否已领奖(0:未领奖 1:已领奖)</td>
</tr>
<tr>
<td>has_watermark</td>
<td>TINYINT</td>
<td>1</td>
<td>NOT NULL</td>
<td>0</td>
<td>是否已生成水印图片(0:未生成 1:已生成)</td>
</tr>
<tr>
<td>remark</td>
<td>VARCHAR</td>
<td>500</td>
<td>NULL</td>
<td>-</td>
<td>备注</td>
</tr>
</tbody>
</table>
<h3 id="workscategory-表">WorksCategory 表</h3>
<table>
<thead>
<tr>
<th>字段名</th>
<th>类型</th>
<th>长度</th>
<th>是否为空</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>category_id</td>
<td>BIGINT</td>
<td>-</td>
<td>NOT NULL</td>
<td>AUTO_INCREMENT</td>
<td>分类ID(主键)</td>
</tr>
<tr>
<td>category_name</td>
<td>VARCHAR</td>
<td>20</td>
<td>NOT NULL</td>
<td>-</td>
<td>分类名称</td>
</tr>
<tr>
<td>category_description</td>
<td>VARCHAR</td>
<td>100</td>
<td>NULL</td>
<td>-</td>
<td>分类描述</td>
</tr>
<tr>
<td>sort_order</td>
<td>INT</td>
<td>-</td>
<td>NOT NULL</td>
<td>0</td>
<td>排序顺序</td>
</tr>
<tr>
<td>is_enabled</td>
<td>TINYINT</td>
<td>1</td>
<td>NOT NULL</td>
<td>1</td>
<td>是否启用(0:禁用 1:启用)</td>
</tr>
<tr>
<td>create_time</td>
<td>DATETIME</td>
<td>-</td>
<td>NOT NULL</td>
<td>CURRENT_TIMESTAMP</td>
<td>创建时间</td>
</tr>
<tr>
<td>update_time</td>
<td>DATETIME</td>
<td>-</td>
<td>NOT NULL</td>
<td>CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP</td>
<td>更新时间</td>
</tr>
<tr>
<td>create_by</td>
<td>VARCHAR</td>
<td>64</td>
<td>NULL</td>
<td>-</td>
<td>创建者</td>
</tr>
<tr>
<td>update_by</td>
<td>VARCHAR</td>
<td>64</td>
<td>NULL</td>
<td>-</td>
<td>更新者</td>
</tr>
</tbody>
</table>
<h3 id="workstag-表">WorksTag 表</h3>
<table>
<thead>
<tr>
<th>字段名</th>
<th>类型</th>
<th>长度</th>
<th>是否为空</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>tag_id</td>
<td>BIGINT</td>
<td>-</td>
<td>NOT NULL</td>
<td>AUTO_INCREMENT</td>
<td>标签ID(主键)</td>
</tr>
<tr>
<td>tag_name</td>
<td>VARCHAR</td>
<td>20</td>
<td>NOT NULL</td>
<td>-</td>
<td>标签名称</td>
</tr>
<tr>
<td>tag_description</td>
<td>VARCHAR</td>
<td>100</td>
<td>NULL</td>
<td>-</td>
<td>标签描述</td>
</tr>
<tr>
<td>sort_order</td>
<td>INT</td>
<td>-</td>
<td>NOT NULL</td>
<td>0</td>
<td>排序顺序</td>
</tr>
<tr>
<td>is_enabled</td>
<td>TINYINT</td>
<td>1</td>
<td>NOT NULL</td>
<td>1</td>
<td>是否启用(0:禁用 1:启用)</td>
</tr>
<tr>
<td>create_time</td>
<td>DATETIME</td>
<td>-</td>
<td>NOT NULL</td>
<td>CURRENT_TIMESTAMP</td>
<td>创建时间</td>
</tr>
<tr>
<td>update_time</td>
<td>DATETIME</td>
<td>-</td>
<td>NOT NULL</td>
<td>CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP</td>
<td>更新时间</td>
</tr>
<tr>
<td>create_by</td>
<td>VARCHAR</td>
<td>64</td>
<td>NULL</td>
<td>-</td>
<td>创建者</td>
</tr>
<tr>
<td>update_by</td>
<td>VARCHAR</td>
<td>64</td>
<td>NULL</td>
<td>-</td>
<td>更新者</td>
</tr>
</tbody>
</table>
<h3 id="worksaward-表">WorksAward 表</h3>
<table>
<thead>
<tr>
<th>字段名</th>
<th>类型</th>
<th>长度</th>
<th>是否为空</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>award_id</td>
<td>BIGINT</td>
<td>-</td>
<td>NOT NULL</td>
<td>AUTO_INCREMENT</td>
<td>获奖等级ID(主键)</td>
</tr>
<tr>
<td>award_name</td>
<td>VARCHAR</td>
<td>20</td>
<td>NOT NULL</td>
<td>-</td>
<td>获奖等级名称</td>
</tr>
<tr>
<td>award_description</td>
<td>VARCHAR</td>
<td>100</td>
<td>NULL</td>
<td>-</td>
<td>获奖等级描述</td>
</tr>

<tr>
<td>sort_order</td>
<td>INT</td>
<td>-</td>
<td>NOT NULL</td>
<td>0</td>
<td>排序顺序</td>
</tr>
<tr>
<td>is_enabled</td>
<td>TINYINT</td>
<td>1</td>
<td>NOT NULL</td>
<td>1</td>
<td>是否启用(0:禁用 1:启用)</td>
</tr>
<tr>
<td>create_time</td>
<td>DATETIME</td>
<td>-</td>
<td>NOT NULL</td>
<td>CURRENT_TIMESTAMP</td>
<td>创建时间</td>
</tr>
<tr>
<td>update_time</td>
<td>DATETIME</td>
<td>-</td>
<td>NOT NULL</td>
<td>CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP</td>
<td>更新时间</td>
</tr>
<tr>
<td>create_by</td>
<td>VARCHAR</td>
<td>64</td>
<td>NULL</td>
<td>-</td>
<td>创建者</td>
</tr>
<tr>
<td>update_by</td>
<td>VARCHAR</td>
<td>64</td>
<td>NULL</td>
<td>-</td>
<td>更新者</td>
</tr>
</tbody>
</table>
<h3 id="worksimage-表">WorksImage 表</h3>
<table>
<thead>
<tr>
<th>字段名</th>
<th>类型</th>
<th>长度</th>
<th>是否为空</th>
<th>默认值</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>image_id</td>
<td>BIGINT</td>
<td>-</td>
<td>NOT NULL</td>
<td>AUTO_INCREMENT</td>
<td>图片ID(主键)</td>
</tr>
<tr>
<td>works_id</td>
<td>BIGINT</td>
<td>-</td>
<td>NOT NULL</td>
<td>-</td>
<td>关联的作品ID</td>
</tr>
<tr>
<td>image_url</td>
<td>VARCHAR</td>
<td>500</td>
<td>NOT NULL</td>
<td>-</td>
<td>图片URL</td>
</tr>
<tr>
<td>thumbnail_url</td>
<td>VARCHAR</td>
<td>500</td>
<td>NULL</td>
<td>-</td>
<td>缩略图URL</td>
</tr>
<tr>
<td>original_name</td>
<td>VARCHAR</td>
<td>255</td>
<td>NOT NULL</td>
<td>-</td>
<td>原始文件名</td>
</tr>
<tr>
<td>file_size</td>
<td>BIGINT</td>
<td>-</td>
<td>NOT NULL</td>
<td>-</td>
<td>文件大小(字节)</td>
</tr>
<tr>
<td>sort_order</td>
<td>INT</td>
<td>-</td>
<td>NOT NULL</td>
<td>0</td>
<td>排序顺序</td>
</tr>
<tr>
<td>upload_time</td>
<td>DATETIME</td>
<td>-</td>
<td>NOT NULL</td>
<td>CURRENT_TIMESTAMP</td>
<td>上传时间</td>
</tr>
<tr>
<td>watermark_url</td>
<td>VARCHAR</td>
<td>500</td>
<td>NULL</td>
<td>-</td>
<td>水印图片URL</td>
</tr>
<tr>
<td>watermark_thumbnail_url</td>
<td>VARCHAR</td>
<td>500</td>
<td>NULL</td>
<td>-</td>
<td>水印缩略图URL</td>
</tr>
<tr>
<td>create_by</td>
<td>VARCHAR</td>
<td>64</td>
<td>NULL</td>
<td>-</td>
<td>创建者</td>
</tr>
</tbody>
</table>
<h3 id="索引设计">索引设计</h3>
<pre><code class="language-sql"><span class="hljs-comment">-- Works表索引</span>
<span class="hljs-keyword">PRIMARY</span> KEY (works_id)
INDEX idx_competition_id (competition_id)
INDEX idx_category_id (category_id)
INDEX idx_award_id (award_id)
INDEX idx_author (author)
INDEX idx_title (title)
INDEX idx_create_time (create_time)
INDEX idx_tag_ids (tag_ids)
INDEX idx_is_author_awarded (is_author_awarded)
INDEX idx_has_watermark (has_watermark)

<span class="hljs-comment">-- WorksCategory表索引    --不去需要索引</span>
<span class="hljs-keyword">PRIMARY</span> KEY (category_id)
<span class="hljs-keyword">UNIQUE</span> INDEX uk_category_name (category_name)
INDEX idx_is_enabled (is_enabled)
INDEX idx_sort_order (sort_order)

<span class="hljs-comment">-- WorksTag表索引 --不去需要索引</span>
<span class="hljs-keyword">PRIMARY</span> KEY (tag_id)
<span class="hljs-keyword">UNIQUE</span> INDEX uk_tag_name (tag_name)
INDEX idx_is_enabled (is_enabled)
INDEX idx_sort_order (sort_order)

<span class="hljs-comment">-- WorksAward表索引 --不去需要索引</span>
<span class="hljs-keyword">PRIMARY</span> KEY (award_id)
<span class="hljs-keyword">UNIQUE</span> INDEX uk_award_name (award_name)
INDEX idx_is_enabled (is_enabled)
INDEX idx_sort_order (sort_order)

<span class="hljs-comment">-- WorksImage表索引 </span>
<span class="hljs-keyword">PRIMARY</span> KEY (image_id)
INDEX idx_works_id (works_id)
INDEX idx_sort_order (sort_order)
</code></pre>
<hr>
<h2 id="错误码说明">错误码说明</h2>
<h3 id="通用错误码">通用错误码</h3>
<table>
<thead>
<tr>
<th>错误码</th>
<th>HTTP状态码</th>
<th>错误信息</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>200</td>
<td>200</td>
<td>操作成功</td>
<td>请求成功</td>
</tr>
<tr>
<td>400</td>
<td>400</td>
<td>请求参数错误</td>
<td>请求参数格式错误或缺少必填参数</td>
</tr>
<tr>
<td>401</td>
<td>401</td>
<td>未授权访问</td>
<td>用户未登录或token无效</td>
</tr>
<tr>
<td>403</td>
<td>403</td>
<td>权限不足</td>
<td>用户权限不足</td>
</tr>
<tr>
<td>404</td>
<td>404</td>
<td>资源不存在</td>
<td>请求的资源不存在</td>
</tr>
<tr>
<td>429</td>
<td>429</td>
<td>请求过于频繁</td>
<td>超出频率限制</td>
</tr>
<tr>
<td>500</td>
<td>500</td>
<td>服务器内部错误</td>
<td>服务器内部错误</td>
</tr>
</tbody>
</table>
<h3 id="作品模块专用错误码">作品模块专用错误码</h3>
<table>
<thead>
<tr>
<th>错误码</th>
<th>HTTP状态码</th>
<th>错误信息</th>
<th>说明</th>
<th>解决方案</th>
</tr>
</thead>
<tbody>
<tr>
<td>5001</td>
<td>400</td>
<td>标签名称不能为空</td>
<td>标签名称为空或格式错误</td>
<td>检查tagName参数</td>
</tr>
<tr>
<td>5002</td>
<td>400</td>
<td>标签名称已存在</td>
<td>标签名称重复</td>
<td>使用不同的标签名称</td>
</tr>
<tr>
<td>5003</td>
<td>400</td>
<td>该类别已有作品引用，无法删除</td>
<td>分类被作品引用</td>
<td>先删除或转移相关作品后再删除分类</td>
</tr>
<tr>
<td>5004</td>
<td>400</td>
<td>分类名称不能为空</td>
<td>分类名称为空或格式错误</td>
<td>检查categoryName参数</td>
</tr>
<tr>
<td>5005</td>
<td>400</td>
<td>分类名称已存在</td>
<td>分类名称重复</td>
<td>使用不同的分类名称</td>
</tr>
<tr>
<td>5006</td>
<td>404</td>
<td>分类不存在</td>
<td>指定的分类不存在</td>
<td>检查categoryId是否正确</td>
</tr>
<tr>
<td>5007</td>
<td>400</td>
<td>获奖等级名称不能为空</td>
<td>获奖等级名称为空或格式错误</td>
<td>检查awardName参数</td>
</tr>
<tr>
<td>5008</td>
<td>400</td>
<td>获奖等级名称已存在</td>
<td>获奖等级名称重复</td>
<td>使用不同的获奖等级名称</td>
</tr>
<tr>
<td>5009</td>
<td>404</td>
<td>获奖等级不存在</td>
<td>指定的获奖等级不存在</td>
<td>检查awardId是否正确</td>
</tr>
<tr>
<td>5010</td>
<td>400</td>
<td>压缩包格式不正确</td>
<td>上传的压缩包格式错误</td>
<td>检查压缩包格式，支持ZIP、RAR、7Z</td>
</tr>
<tr>
<td>5011</td>
<td>400</td>
<td>压缩包目录结构不符合规范</td>
<td>压缩包内目录结构错误</td>
<td>按照规范重新组织目录结构</td>
</tr>
<tr>
<td>5012</td>
<td>400</td>
<td>压缩包大小超限</td>
<td>压缩包大小超过限制</td>
<td>压缩包大小不能超过1GB</td>
</tr>
<tr>
<td>5013</td>
<td>400</td>
<td>压缩包解压失败</td>
<td>压缩包解压过程中发生错误</td>
<td>检查压缩包是否损坏</td>
</tr>
<tr>
<td>5014</td>
<td>400</td>
<td>图片格式不支持</td>
<td>图片格式不支持</td>
<td>仅支持JPG、PNG、WEBP格式</td>
</tr>
<tr>
<td>5015</td>
<td>400</td>
<td>图片大小超限</td>
<td>单个图片大小超过限制</td>
<td>单个图片不能超过10MB</td>
</tr>
<tr>
<td>5016</td>
<td>500</td>
<td>图片上传COS失败</td>
<td>图片上传到腾讯云COS失败</td>
<td>检查COS配置和网络连接</td>
</tr>
<tr>
<td>5017</td>
<td>500</td>
<td>缩略图生成失败</td>
<td>缩略图生成过程中发生错误</td>
<td>检查图片处理服务状态</td>
</tr>
<tr>
<td>5029</td>
<td>400</td>
<td>上传任务不存在</td>
<td>指定的上传任务不存在</td>
<td>检查uploadId是否正确</td>
</tr>
<tr>
<td>5030</td>
<td>400</td>
<td>上传任务已过期</td>
<td>上传任务超过有效期</td>
<td>重新开始上传流程</td>
</tr>
<tr>
<td>5031</td>
<td>429</td>
<td>并发上传超限</td>
<td>超过最大并发上传数限制</td>
<td>等待其他任务完成后重试</td>
</tr>
<tr>
<td>5032</td>
<td>400</td>
<td>上传任务状态错误</td>
<td>当前任务状态不允许此操作</td>
<td>检查任务状态后重试</td>
</tr>
<tr>
<td>5033</td>
<td>500</td>
<td>WebSocket连接失败</td>
<td>进度推送连接建立失败</td>
<td>检查WebSocket配置</td>
</tr>
<tr>
<td>5034</td>
<td>400</td>
<td>批次不存在</td>
<td>指定的批次不存在</td>
<td>检查batchId是否正确</td>
</tr>
<tr>
<td>5035</td>
<td>400</td>
<td>批次已回滚</td>
<td>批次已经被回滚，无法重复操作</td>
<td>批次状态已为ROLLBACKED</td>
</tr>
<tr>
<td>5018</td>
<td>404</td>
<td>作品不存在</td>
<td>指定的作品不存在</td>
<td>检查worksId是否正确</td>
</tr>
<tr>
<td>5019</td>
<td>404</td>
<td>比赛活动不存在</td>
<td>指定的比赛活动不存在</td>
<td>检查competitionId是否正确</td>
</tr>
<tr>
<td>5020</td>
<td>400</td>
<td>作品标题不能为空</td>
<td>作品标题为空或格式错误</td>
<td>检查title参数</td>
</tr>
<tr>
<td>5021</td>
<td>400</td>
<td>作者姓名不能为空</td>
<td>作者姓名为空或格式错误</td>
<td>检查author参数</td>
</tr>
<tr>
<td>5022</td>
<td>400</td>
<td>评语内容过长</td>
<td>评语内容超过最大长度限制</td>
<td>评语内容不能超过500字符</td>
</tr>
<tr>
<td>5023</td>
<td>500</td>
<td>腾讯云COS文件删除失败</td>
<td>腾讯云COS文件删除失败</td>
<td>检查腾讯云COS配置和权限</td>
</tr>
<tr>
<td>5036</td>
<td>500</td>
<td>批量文件删除失败</td>
<td>批量删除腾讯云COS文件时部分失败</td>
<td>检查失败文件列表和COS权限</td>
</tr>
<tr>
<td>5024</td>
<td>400</td>
<td>临时文件已过期</td>
<td>临时上传的文件已过期</td>
<td>重新上传文件</td>
</tr>
<tr>
<td>5025</td>
<td>400</td>
<td>作品图片不存在</td>
<td>指定的作品图片不存在</td>
<td>检查imageId是否正确</td>
</tr>
<tr>
<td>5026</td>
<td>408</td>
<td>大文件处理超时</td>
<td>大容量压缩包处理超时</td>
<td>检查文件大小，建议分批上传</td>
</tr>
<tr>
<td>5027</td>
<td>507</td>
<td>内存不足</td>
<td>处理大文件时内存不足</td>
<td>减少文件大小或联系管理员</td>
</tr>
<tr>
<td>5028</td>
<td>400</td>
<td>压缩包内文件过多</td>
<td>压缩包内图片文件数量超限</td>
<td>单个作品最多包含50张图片</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="业务逻辑说明">业务逻辑说明</h2>
<h3 id="分步骤作品上传规则">分步骤作品上传规则</h3>
<h4 id="第一步压缩包上传">第一步：压缩包上传</h4>
<ol>
<li><strong>压缩包格式</strong>：支持ZIP、RAR、7Z格式</li>
<li><strong>格式检测</strong>：自动检测压缩包格式并选择对应的解压工具</li>
<li><strong>并发控制</strong>：普通用户最多1个上传任务，管理员最多3个任务</li>
<li><strong>临时存储</strong>：压缩包先存储到服务器本地临时目录，7天后自动清理</li>
<li><strong>任务超时</strong>：上传任务60分钟超时，超时后自动取消</li>
<li><strong>文件大小限制</strong>：压缩包最大1GB，单个图片最大10MB</li>
</ol>
<h4 id="第二步解析并上传cos">第二步：解析并上传COS</h4>
<ol>
<li><strong>目录结构验证</strong>：严格按照&quot;分类/作者@标题/图片&quot;的三级目录结构</li>
<li><strong>分类自动创建</strong>：如果分类不存在，系统自动创建新分类</li>
<li><strong>重复检查</strong>：检查&quot;活动/分类/作者@作品标题&quot;的唯一性</li>
<li><strong>图片重命名</strong>：上传到COS前进行重命名，格式为&quot;原名_时间戳.扩展名&quot;</li>
<li><strong>缩略图生成</strong>：自动生成200x200像素的缩略图</li>
<li><strong>进度监控</strong>：通过WebSocket实时推送上传进度</li>
<li><strong>分块上传</strong>：大文件采用8MB分块上传到腾讯云COS</li>
<li><strong>文件数量限制</strong>：单个作品最多包含50张图片文件</li>
<li><strong>错误重试</strong>：上传失败自动重试最多3次</li>
</ol>
<h3 id="图片处理流程详解">图片处理流程详解</h3>
<h4 id="压缩包处理阶段">压缩包处理阶段</h4>
<ol>
<li>
<p><strong>文件接收</strong>：</p>
<ul>
<li>压缩包上传到服务器本地临时目录 <code>${ruoyi.profile}/temp/works/uploads/{uploadId}/</code></li>
<li>生成唯一的上传任务ID（uploadId）</li>
<li>记录上传时间和文件信息</li>
</ul>
</li>
<li>
<p><strong>压缩包解压</strong>：</p>
<ul>
<li>检测压缩包格式（ZIP/RAR/7Z）</li>
<li>解压到本地临时目录 <code>${ruoyi.profile}/temp/works/extracted/{uploadId}/</code></li>
<li>验证目录结构：<code>分类/作者@标题/图片文件</code></li>
<li>过滤非图片文件，只保留 JPG、PNG、WEBP 格式</li>
</ul>
</li>
</ol>
<h4 id="图片处理阶段">图片处理阶段</h4>
<ol start="3">
<li>
<p><strong>图片预处理</strong>：</p>
<ul>
<li>读取图片文件到内存（使用 BufferedInputStream 避免大文件内存溢出）</li>
<li>验证图片格式和完整性</li>
<li>检查图片尺寸和文件大小限制</li>
<li>重命名文件：<code>{原文件名}_{时间戳}.{扩展名}</code></li>
</ul>
</li>
<li>
<p><strong>缩略图生成</strong>：</p>
<ul>
<li>使用 Thumbnailator 库进行图片缩放</li>
<li>目标尺寸：200x200像素</li>
<li>保持宽高比，不足部分用白色填充</li>
<li>输出格式：JPEG，质量80%</li>
<li>保存到本地临时目录 <code>${ruoyi.profile}/temp/works/processed/{uploadId}/thumbnails/</code></li>
</ul>
</li>
<li>
<p><strong>图片优化</strong>：</p>
<ul>
<li>原图质量压缩至90%（可配置）</li>
<li>大图片自动缩放（最大边不超过2048px）</li>
<li>保存到本地临时目录 <code>${ruoyi.profile}/temp/works/processed/{uploadId}/images/</code></li>
</ul>
</li>
</ol>
<h4 id="云存储上传阶段">云存储上传阶段</h4>
<ol start="6">
<li>
<p><strong>腾讯云COS上传</strong>：</p>
<ul>
<li>原图上传到 <code>works/images/{worksId}/</code></li>
<li>缩略图上传到 <code>works/thumbnails/{worksId}/</code></li>
<li>大文件（&gt;8MB）采用分块上传</li>
<li>设置文件访问权限为公共读</li>
<li>配置CDN缓存策略</li>
</ul>
</li>
<li>
<p><strong>数据库记录</strong>：</p>
<ul>
<li>保存作品基本信息到 <code>shufa_works</code> 表</li>
<li>保存图片信息到 <code>shufa_works_images</code> 表</li>
<li>记录 <code>imageUrl</code> 和 <code>thumbnailUrl</code> 为完整的COS访问路径</li>
</ul>
</li>
<li>
<p><strong>清理临时文件</strong>：</p>
<ul>
<li>上传成功后立即删除本地临时文件</li>
<li>失败时保留临时文件用于重试</li>
<li>定时任务清理7天前的临时文件</li>
</ul>
</li>
</ol>
<h4 id="技术实现要点">技术实现要点</h4>
<ul>
<li><strong>内存控制</strong>：使用流式处理，避免大文件导致内存溢出</li>
<li><strong>并发处理</strong>：使用线程池处理图片压缩和上传任务</li>
<li><strong>错误处理</strong>：详细的异常捕获和错误码返回</li>
<li><strong>进度反馈</strong>：通过WebSocket实时推送处理进度</li>
<li><strong>事务管理</strong>：数据库操作使用事务确保数据一致性</li>
</ul>
<h4 id="第三步确认导入配置">第三步：确认导入配置</h4>
<ol>
<li><strong>默认标签</strong>：新上传的作品默认添加&quot;首页&quot;标签(tagId=0)</li>
<li><strong>默认获奖等级</strong>：新上传的作品默认为&quot;未获奖&quot;状态</li>
<li><strong>批次记录</strong>：生成批次ID，记录上传信息用于后续回滚</li>
<li><strong>数据库事务</strong>：采用事务批处理确保数据一致性</li>
<li><strong>缓存更新</strong>：清理相关缓存，确保数据实时性</li>
<li><strong>持久化存储</strong>：将临时文件移动到正式存储目录</li>
</ol>
<h3 id="作品分类管理规则">作品分类管理规则</h3>
<ol>
<li><strong>唯一性约束</strong>：分类名称必须唯一</li>
<li><strong>引用检查</strong>：删除分类前检查是否有作品引用</li>
<li><strong>自动创建</strong>：批量上传时可自动创建不存在的分类</li>
<li><strong>排序支持</strong>：支持自定义排序顺序</li>
</ol>
<h3 id="作品标签管理规则">作品标签管理规则</h3>
<ol>
<li><strong>默认标签</strong>：系统预置&quot;首页&quot;(ID=0)和&quot;优秀作品&quot;(ID=1)标签</li>
<li><strong>多标签支持</strong>：每个作品可以关联多个标签</li>
<li><strong>标签唯一性</strong>：标签名称必须唯一</li>
<li><strong>首页标签</strong>：ID为0的标签为首页标签，不可删除</li>
</ol>
<h3 id="获奖等级管理规则">获奖等级管理规则</h3>
<ol>
<li><strong>等级排序</strong>：按照awardLevel字段进行等级排序</li>
<li><strong>默认等级</strong>：系统预置&quot;特等奖&quot;、&quot;一等奖&quot;、&quot;二等奖&quot;、&quot;三等奖&quot;、&quot;优秀奖&quot;、&quot;未获奖&quot;</li>
<li><strong>未获奖默认</strong>：新作品默认为&quot;未获奖&quot;状态</li>
<li><strong>等级唯一性</strong>：获奖等级名称必须唯一</li>
</ol>
<h3 id="作品展示规则">作品展示规则</h3>
<ol>
<li><strong>App端限制</strong>：App端只能查看当前活动的作品</li>
<li><strong>首页展示</strong>：标签包含&quot;首页&quot;(ID=0)的作品在首页展示</li>
<li><strong>优秀作品</strong>：标签包含&quot;优秀作品&quot;(ID=1)的作品在优秀作品页展示</li>
<li><strong>评语展示</strong>：根据commentDisplayLength字段控制评语展示长度</li>
<li><strong>图片排序</strong>：作品图片按照sortOrder字段排序展示</li>
</ol>
<h3 id="文件存储规则">文件存储规则</h3>
<ul>
<li><strong>腾讯云COS存储</strong>：所有正式图片文件存储在腾讯云COS中</li>
<li><strong>服务器本地临时存储</strong>：压缩包解压和图片处理在服务器本地进行</li>
<li><strong>腾讯云COS目录结构</strong>：<pre><code>works/
├── images/           # 原图
│   └── {worksId}/    # 按作品ID分组
└── thumbnails/       # 缩略图
    └── {worksId}/    # 按作品ID分组
</code></pre>
</li>
<li><strong>服务器本地临时目录结构</strong>：<pre><code>${ruoyi.profile}/temp/works/
├── uploads/          # 上传的压缩包
│   └── {uploadId}/   # 按上传任务ID分组
├── extracted/        # 解压后的文件
│   └── {uploadId}/   # 按上传任务ID分组
└── processed/        # 处理后的图片（待上传COS）
    └── {uploadId}/   # 按上传任务ID分组
</code></pre>
</li>
<li><strong>文件命名规则</strong>: <code>{原文件名}_{时间戳}.{扩展名}</code>
<ul>
<li>原文件名: 去除特殊字符后的原始文件名</li>
<li>时间戳: Unix时间戳(毫秒)</li>
<li>扩展名: jpg、png、webp</li>
<li>示例：<code>海阔天空1_1704067200123.jpg</code></li>
</ul>
</li>
<li><strong>文件格式</strong>：支持 JPG、PNG、WEBP</li>
<li><strong>文件大小</strong>：单个图片不超过10MB，压缩包不超过1GB</li>
<li><strong>缩略图规格</strong>：200x200像素，JPEG格式，质量80%</li>
<li><strong>分块上传</strong>：大于8MB的文件采用分块上传</li>
<li><strong>CDN加速</strong>：通过CDN域名访问，提高访问速度</li>
</ul>
<h3 id="大文件处理策略">大文件处理策略</h3>
<ul>
<li><strong>流式处理</strong>：采用流式读取和处理，避免将整个压缩包加载到内存</li>
<li><strong>分块上传</strong>：大文件分块上传到腾讯云COS，提高上传成功率</li>
<li><strong>进度监控</strong>：提供上传进度反馈，支持断点续传</li>
<li><strong>超时控制</strong>：设置合理的超时时间，防止长时间占用资源</li>
<li><strong>内存优化</strong>：
<ul>
<li>使用缓冲流减少内存占用</li>
<li>及时释放临时文件和内存资源</li>
<li>设置JVM堆内存参数适应大文件处理</li>
</ul>
</li>
<li><strong>错误恢复</strong>：
<ul>
<li>上传失败时自动重试（最多3次）</li>
<li>提供详细的错误信息和处理建议</li>
<li>支持部分成功的作品保存</li>
</ul>
</li>
</ul>
<h3 id="垃圾文件清理机制">垃圾文件清理机制</h3>
<ul>
<li><strong>临时文件管理</strong>：</li>
<li>压缩包上传后存储在服务器本地临时目录</li>
<li>解压和图片处理在服务器本地进行</li>
<li>处理完成后上传到腾讯云COS正式目录</li>
<li>本地临时文件7天后自动清理（配置可调）</li>
<li><strong>删除作品清理</strong>：
<ul>
<li>删除作品时同步删除腾讯云COS上的所有相关图片</li>
<li>包括原图和缩略图</li>
</ul>
</li>
<li><strong>定时清理任务</strong>：
<ul>
<li>每日凌晨3点执行垃圾文件清理</li>
<li>清理未被任何作品引用的图片文件</li>
<li>清理temp目录中的过期文件</li>
</ul>
</li>
<li><strong>失败重试机制</strong>：
<ul>
<li>腾讯云COS删除失败的文件记录到清理队列</li>
<li>定时任务会重试删除失败的文件</li>
</ul>
</li>
</ul>
<hr>
<h2 id="缓存策略">缓存策略</h2>
<h3 id="首页作品缓存">首页作品缓存</h3>
<ul>
<li><strong>缓存键</strong>：<code>works:homepage:page:{pageNum}:size:{pageSize}</code></li>
<li><strong>缓存时间</strong>：30分钟（1800秒）</li>
<li><strong>缓存内容</strong>：首页作品列表数据</li>
<li><strong>更新策略</strong>：作品标签变更时清除相关缓存</li>
<li><strong>降级策略</strong>：缓存失效时直接查询数据库</li>
</ul>
<h3 id="作品详情缓存">作品详情缓存</h3>
<ul>
<li><strong>缓存键</strong>：<code>works:detail:{worksId}</code></li>
<li><strong>缓存时间</strong>：1小时（3600秒）</li>
<li><strong>缓存内容</strong>：作品详情数据（包括图片列表）</li>
<li><strong>更新策略</strong>：作品信息变更时清除对应缓存</li>
<li><strong>降级策略</strong>：缓存失效时直接查询数据库</li>
</ul>
<h3 id="分类标签缓存">分类标签缓存</h3>
<ul>
<li><strong>缓存键</strong>：<code>works:categories:enabled</code> / <code>works:tags:enabled</code> / <code>works:awards:enabled</code></li>
<li><strong>缓存时间</strong>：2小时（7200秒）</li>
<li><strong>缓存内容</strong>：启用状态的分类、标签、获奖等级列表</li>
<li><strong>更新策略</strong>：相关数据变更时清除对应缓存</li>
<li><strong>降级策略</strong>：缓存失效时直接查询数据库</li>
</ul>
<hr>
<h2 id="文件管理策略">文件管理策略</h2>
<h3 id="腾讯云cos存储配置">腾讯云COS存储配置</h3>
<ul>
<li><strong>存储方式</strong>：腾讯云COS对象存储</li>
<li><strong>访问方式</strong>：通过CDN加速访问</li>
<li><strong>图片处理</strong>：支持实时缩放、格式转换、质量压缩</li>
<li><strong>缓存策略</strong>：CDN缓存30天，浏览器缓存7天</li>
</ul>
<h3 id="图片处理规则">图片处理规则</h3>
<ul>
<li><strong>缩略图生成</strong>：自动生成200x200像素缩略图</li>
<li><strong>格式转换</strong>：支持WebP格式优化</li>
<li><strong>质量压缩</strong>：原图质量90%，缩略图质量80%</li>
<li><strong>水印添加</strong>：可选择性添加版权水印</li>
</ul>
<hr>
<h2 id="安全注意事项">安全注意事项</h2>
<ol>
<li><strong>权限控制</strong>：管理接口必须验证管理员权限</li>
<li><strong>参数验证</strong>：严格验证所有输入参数</li>
<li><strong>文件安全</strong>：验证上传文件类型和大小</li>
<li><strong>SQL注入防护</strong>：使用参数化查询</li>
<li><strong>XSS防护</strong>：对输出内容进行HTML转义</li>
<li><strong>频率限制</strong>：实施接口调用频率限制</li>
<li><strong>日志记录</strong>：记录所有管理操作日志</li>
<li><strong>敏感信息保护</strong>：不在日志中记录敏感信息</li>
</ol>
<hr>
<h2 id="配置要求">配置要求</h2>
<h3 id="系统配置">系统配置</h3>
<h4 id="若依框架配置扩展">若依框架配置扩展</h4>
<pre><code class="language-yaml"><span class="hljs-comment"># application-works.yml</span>
<span class="hljs-attr">ruoyi:</span>
  <span class="hljs-comment"># 扩展若依配置</span>
  <span class="hljs-attr">works:</span>
    <span class="hljs-comment"># 缓存配置</span>
    <span class="hljs-attr">cache:</span>
      <span class="hljs-attr">homepage-ttl:</span> <span class="hljs-number">1800</span>      <span class="hljs-comment"># 首页作品缓存时间(秒)</span>
      <span class="hljs-attr">excellent-ttl:</span> <span class="hljs-number">1800</span>     <span class="hljs-comment"># 优秀作品缓存时间(秒)</span>
      <span class="hljs-attr">detail-ttl:</span> <span class="hljs-number">3600</span>        <span class="hljs-comment"># 作品详情缓存时间(秒)</span>
      <span class="hljs-attr">category-ttl:</span> <span class="hljs-number">7200</span>      <span class="hljs-comment"># 分类标签缓存时间(秒)</span>
      <span class="hljs-attr">enable-cache-warmup:</span> <span class="hljs-literal">true</span> <span class="hljs-comment"># 启用缓存预热</span>
    
    <span class="hljs-comment"># 分步骤上传配置(扩展若依上传配置)</span>
    <span class="hljs-attr">upload:</span>
      <span class="hljs-attr">max-zip-size:</span> <span class="hljs-number">1073741824</span>   <span class="hljs-comment"># 最大压缩包大小(1GB)</span>
      <span class="hljs-attr">max-image-size:</span> <span class="hljs-number">10485760</span>  <span class="hljs-comment"># 最大图片大小(10MB)</span>
      <span class="hljs-attr">allowed-image-types:</span> <span class="hljs-string">jpg,jpeg,png,webp</span>
      <span class="hljs-attr">allowed-compress-types:</span> <span class="hljs-string">zip,rar,7z</span>  <span class="hljs-comment"># 支持的压缩格式</span>
      <span class="hljs-attr">temp-dir:</span> <span class="hljs-string">${ruoyi.profile}/temp/works</span>  <span class="hljs-comment"># 临时文件目录</span>
      <span class="hljs-attr">temp-cleanup-days:</span> <span class="hljs-number">7</span>      <span class="hljs-comment"># 临时文件清理天数</span>
      <span class="hljs-attr">persistent-storage:</span> <span class="hljs-literal">true</span>  <span class="hljs-comment"># 是否持久化存储</span>
      <span class="hljs-attr">max-concurrent-uploads:</span> <span class="hljs-number">3</span> <span class="hljs-comment"># 最大并发上传数(管理员)</span>
      <span class="hljs-attr">max-user-uploads:</span> <span class="hljs-number">1</span>       <span class="hljs-comment"># 普通用户最大并发数</span>
      <span class="hljs-attr">upload-timeout-minutes:</span> <span class="hljs-number">60</span> <span class="hljs-comment"># 上传任务超时时间(分钟)</span>
      <span class="hljs-attr">progress-websocket-path:</span> <span class="hljs-string">/ws/upload/progress</span> <span class="hljs-comment"># WebSocket进度推送路径</span>
      <span class="hljs-attr">enable-progress-monitor:</span> <span class="hljs-literal">true</span> <span class="hljs-comment"># 启用进度监控</span>
      <span class="hljs-attr">chunk-upload-size:</span> <span class="hljs-number">8388608</span>    <span class="hljs-comment"># 分块上传大小(8MB)</span>
    
    <span class="hljs-comment"># 图片处理配置</span>
    <span class="hljs-attr">image:</span>
      <span class="hljs-attr">thumbnail-size:</span> <span class="hljs-number">200</span>       <span class="hljs-comment"># 缩略图尺寸</span>
      <span class="hljs-attr">thumbnail-quality:</span> <span class="hljs-number">80</span>     <span class="hljs-comment"># 缩略图质量</span>
      <span class="hljs-attr">original-quality:</span> <span class="hljs-number">90</span>      <span class="hljs-comment"># 原图质量</span>
      <span class="hljs-attr">enable-watermark:</span> <span class="hljs-literal">false</span>   <span class="hljs-comment"># 启用水印</span>
      <span class="hljs-attr">watermark-text:</span> <span class="hljs-string">&quot;书法作品&quot;</span> <span class="hljs-comment"># 水印文字</span>
    
    <span class="hljs-comment"># 定时任务配置</span>
    <span class="hljs-attr">task:</span>
      <span class="hljs-attr">cleanup-cron:</span> <span class="hljs-string">&quot;0 0 3 * * ?&quot;</span>  <span class="hljs-comment"># 每日凌晨3点执行清理</span>
      <span class="hljs-attr">enable-cleanup:</span> <span class="hljs-literal">true</span>      <span class="hljs-comment"># 启用自动清理</span>
    
    <span class="hljs-comment"># 大文件处理配置</span>
    <span class="hljs-attr">large-file:</span>
      <span class="hljs-attr">max-processing-time:</span> <span class="hljs-number">60000</span>  <span class="hljs-comment"># 最大处理时间(毫秒)</span>
      <span class="hljs-attr">chunk-size:</span> <span class="hljs-number">8388608</span>        <span class="hljs-comment"># 分块大小(8MB)</span>
      <span class="hljs-attr">max-retry-times:</span> <span class="hljs-number">3</span>         <span class="hljs-comment"># 最大重试次数</span>
      <span class="hljs-attr">enable-progress-monitor:</span> <span class="hljs-literal">true</span> <span class="hljs-comment"># 启用进度监控</span>
      <span class="hljs-attr">temp-buffer-size:</span> <span class="hljs-number">1048576</span>  <span class="hljs-comment"># 临时缓冲区大小(1MB)</span>

<span class="hljs-comment"># Spring Boot配置扩展</span>
<span class="hljs-attr">spring:</span>
  <span class="hljs-attr">servlet:</span>
    <span class="hljs-attr">multipart:</span>
      <span class="hljs-attr">max-file-size:</span> <span class="hljs-string">1GB</span>         <span class="hljs-comment"># 最大文件大小</span>
      <span class="hljs-attr">max-request-size:</span> <span class="hljs-string">1GB</span>      <span class="hljs-comment"># 最大请求大小</span>
      <span class="hljs-attr">file-size-threshold:</span> <span class="hljs-string">10MB</span>  <span class="hljs-comment"># 文件大小阈值</span>
  
  <span class="hljs-comment"># 任务执行器配置(用于大文件异步处理)</span>
  <span class="hljs-attr">task:</span>
    <span class="hljs-attr">execution:</span>
      <span class="hljs-attr">pool:</span>
        <span class="hljs-attr">core-size:</span> <span class="hljs-number">4</span>
        <span class="hljs-attr">max-size:</span> <span class="hljs-number">8</span>
        <span class="hljs-attr">queue-capacity:</span> <span class="hljs-number">100</span>
        <span class="hljs-attr">keep-alive:</span> <span class="hljs-string">60s</span>
      <span class="hljs-attr">thread-name-prefix:</span> <span class="hljs-string">works-upload-</span>

<span class="hljs-comment"># 腾讯云COS配置</span>
<span class="hljs-attr">cos:</span>
  <span class="hljs-attr">region:</span> <span class="hljs-string">ap-beijing</span>
  <span class="hljs-attr">secret-id:</span> <span class="hljs-string">${COS_SECRET_ID}</span>
  <span class="hljs-attr">secret-key:</span> <span class="hljs-string">${COS_SECRET_KEY}</span>
  <span class="hljs-attr">bucket-name:</span> <span class="hljs-string">shufa-works-1234567890</span>
  <span class="hljs-attr">base-path:</span> <span class="hljs-string">works/</span>
  <span class="hljs-attr">cdn-domain:</span> <span class="hljs-string">https://cdn.shufa.com</span>
  <span class="hljs-attr">upload-timeout:</span> <span class="hljs-number">300000</span>  <span class="hljs-comment"># 上传超时时间(毫秒)</span>
  <span class="hljs-attr">max-connections:</span> <span class="hljs-number">100</span>    <span class="hljs-comment"># 最大连接数</span>
  <span class="hljs-attr">socket-timeout:</span> <span class="hljs-number">30000</span>   <span class="hljs-comment"># Socket超时时间(毫秒)</span>
  <span class="hljs-attr">connection-timeout:</span> <span class="hljs-number">5000</span> <span class="hljs-comment"># 连接超时时间(毫秒)</span>
  
<span class="hljs-comment"># Redis配置(基于若依Redis配置扩展)</span>
<span class="hljs-attr">spring:</span>
  <span class="hljs-attr">redis:</span>
    <span class="hljs-attr">host:</span> <span class="hljs-string">localhost</span>
    <span class="hljs-attr">port:</span> <span class="hljs-number">6379</span>
    <span class="hljs-attr">password:</span> 
    <span class="hljs-attr">database:</span> <span class="hljs-number">1</span>
    <span class="hljs-attr">timeout:</span> <span class="hljs-string">10s</span>
    <span class="hljs-attr">lettuce:</span>
      <span class="hljs-attr">pool:</span>
        <span class="hljs-attr">max-active:</span> <span class="hljs-number">200</span>
        <span class="hljs-attr">max-wait:</span> <span class="hljs-string">-1ms</span>
        <span class="hljs-attr">max-idle:</span> <span class="hljs-number">10</span>
        <span class="hljs-attr">min-idle:</span> <span class="hljs-number">0</span>

<span class="hljs-comment"># JVM配置建议(用于大文件处理)</span>
<span class="hljs-comment"># -Xmx4g -Xms2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200</span>
<span class="hljs-comment"># -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/</span>
<span class="hljs-comment"># -Djava.io.tmpdir=/tmp/works-upload/</span>
</code></pre>
<h4 id="权限配置">权限配置</h4>
<pre><code class="language-sql"><span class="hljs-comment">-- 菜单权限配置(插入到若依sys_menu表)</span>
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sys_menu <span class="hljs-keyword">VALUES</span> 
(<span class="hljs-number">2200</span>, <span class="hljs-string">&#x27;作品管理&#x27;</span>, <span class="hljs-number">0</span>, <span class="hljs-number">7</span>, <span class="hljs-string">&#x27;works&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;M&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;works&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;作品管理&#x27;</span>),
(<span class="hljs-number">2201</span>, <span class="hljs-string">&#x27;作品列表&#x27;</span>, <span class="hljs-number">2200</span>, <span class="hljs-number">1</span>, <span class="hljs-string">&#x27;list&#x27;</span>, <span class="hljs-string">&#x27;works/list/index&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;C&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:list:list&#x27;</span>, <span class="hljs-string">&#x27;list&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;作品列表&#x27;</span>),
(<span class="hljs-number">2202</span>, <span class="hljs-string">&#x27;作品新增&#x27;</span>, <span class="hljs-number">2201</span>, <span class="hljs-number">1</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:list:add&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2203</span>, <span class="hljs-string">&#x27;作品修改&#x27;</span>, <span class="hljs-number">2201</span>, <span class="hljs-number">2</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:list:edit&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2204</span>, <span class="hljs-string">&#x27;作品删除&#x27;</span>, <span class="hljs-number">2201</span>, <span class="hljs-number">3</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:list:remove&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2205</span>, <span class="hljs-string">&#x27;作品查询&#x27;</span>, <span class="hljs-number">2201</span>, <span class="hljs-number">4</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:list:query&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2206</span>, <span class="hljs-string">&#x27;批量上传&#x27;</span>, <span class="hljs-number">2201</span>, <span class="hljs-number">5</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:list:upload&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2210</span>, <span class="hljs-string">&#x27;作品分类&#x27;</span>, <span class="hljs-number">2200</span>, <span class="hljs-number">2</span>, <span class="hljs-string">&#x27;category&#x27;</span>, <span class="hljs-string">&#x27;works/category/index&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;C&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:category:list&#x27;</span>, <span class="hljs-string">&#x27;category&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;作品分类管理&#x27;</span>),
(<span class="hljs-number">2211</span>, <span class="hljs-string">&#x27;分类新增&#x27;</span>, <span class="hljs-number">2210</span>, <span class="hljs-number">1</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:category:add&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2212</span>, <span class="hljs-string">&#x27;分类修改&#x27;</span>, <span class="hljs-number">2210</span>, <span class="hljs-number">2</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:category:edit&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2213</span>, <span class="hljs-string">&#x27;分类删除&#x27;</span>, <span class="hljs-number">2210</span>, <span class="hljs-number">3</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:category:remove&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2220</span>, <span class="hljs-string">&#x27;作品标签&#x27;</span>, <span class="hljs-number">2200</span>, <span class="hljs-number">3</span>, <span class="hljs-string">&#x27;tag&#x27;</span>, <span class="hljs-string">&#x27;works/tag/index&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;C&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:tag:list&#x27;</span>, <span class="hljs-string">&#x27;tag&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;作品标签管理&#x27;</span>),
(<span class="hljs-number">2221</span>, <span class="hljs-string">&#x27;标签新增&#x27;</span>, <span class="hljs-number">2220</span>, <span class="hljs-number">1</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:tag:add&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2222</span>, <span class="hljs-string">&#x27;标签修改&#x27;</span>, <span class="hljs-number">2220</span>, <span class="hljs-number">2</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:tag:edit&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2223</span>, <span class="hljs-string">&#x27;标签删除&#x27;</span>, <span class="hljs-number">2220</span>, <span class="hljs-number">3</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:tag:remove&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2230</span>, <span class="hljs-string">&#x27;获奖等级&#x27;</span>, <span class="hljs-number">2200</span>, <span class="hljs-number">4</span>, <span class="hljs-string">&#x27;award&#x27;</span>, <span class="hljs-string">&#x27;works/award/index&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;C&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:award:list&#x27;</span>, <span class="hljs-string">&#x27;award&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;获奖等级管理&#x27;</span>),
(<span class="hljs-number">2231</span>, <span class="hljs-string">&#x27;等级新增&#x27;</span>, <span class="hljs-number">2230</span>, <span class="hljs-number">1</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:award:add&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2232</span>, <span class="hljs-string">&#x27;等级修改&#x27;</span>, <span class="hljs-number">2230</span>, <span class="hljs-number">2</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:award:edit&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>),
(<span class="hljs-number">2233</span>, <span class="hljs-string">&#x27;等级删除&#x27;</span>, <span class="hljs-number">2230</span>, <span class="hljs-number">3</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-string">&#x27;F&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;0&#x27;</span>, <span class="hljs-string">&#x27;works:award:remove&#x27;</span>, <span class="hljs-string">&#x27;#&#x27;</span>, <span class="hljs-string">&#x27;admin&#x27;</span>, sysdate(), <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-keyword">NULL</span>, <span class="hljs-string">&#x27;&#x27;</span>);
</code></pre>
<h3 id="数据库初始化">数据库初始化</h3>
<pre><code class="language-sql"><span class="hljs-comment">-- 创建作品相关表</span>
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> works_category (
  category_id <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;分类ID&#x27;</span>,
  category_name <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;分类名称&#x27;</span>,
  category_description <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;分类描述&#x27;</span>,
  sort_order <span class="hljs-type">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">&#x27;排序顺序&#x27;</span>,
  is_enabled TINYINT(<span class="hljs-number">1</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">1</span> COMMENT <span class="hljs-string">&#x27;是否启用(0:禁用 1:启用)&#x27;</span>,
  create_time DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;创建时间&#x27;</span>,
  update_time DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> <span class="hljs-keyword">ON</span> <span class="hljs-keyword">UPDATE</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;更新时间&#x27;</span>,
  create_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;创建者&#x27;</span>,
  update_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;更新者&#x27;</span>,
  <span class="hljs-keyword">PRIMARY</span> KEY (category_id),
  <span class="hljs-keyword">UNIQUE</span> INDEX uk_category_name (category_name),
  INDEX idx_is_enabled (is_enabled),
  INDEX idx_sort_order (sort_order)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8mb4 COMMENT<span class="hljs-operator">=</span><span class="hljs-string">&#x27;作品分类表&#x27;</span>;

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> works_tag (
  tag_id <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;标签ID&#x27;</span>,
  tag_name <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;标签名称&#x27;</span>,
  tag_description <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;标签描述&#x27;</span>,
  sort_order <span class="hljs-type">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">&#x27;排序顺序&#x27;</span>,
  is_enabled TINYINT(<span class="hljs-number">1</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">1</span> COMMENT <span class="hljs-string">&#x27;是否启用(0:禁用 1:启用)&#x27;</span>,
  create_time DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;创建时间&#x27;</span>,
  update_time DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> <span class="hljs-keyword">ON</span> <span class="hljs-keyword">UPDATE</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;更新时间&#x27;</span>,
  create_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;创建者&#x27;</span>,
  update_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;更新者&#x27;</span>,
  <span class="hljs-keyword">PRIMARY</span> KEY (tag_id),
  <span class="hljs-keyword">UNIQUE</span> INDEX uk_tag_name (tag_name),
  INDEX idx_is_enabled (is_enabled),
  INDEX idx_sort_order (sort_order)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8mb4 COMMENT<span class="hljs-operator">=</span><span class="hljs-string">&#x27;作品标签表&#x27;</span>;

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> works_award (
  award_id <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;获奖等级ID&#x27;</span>,
  award_name <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;获奖等级名称&#x27;</span>,
  award_description <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;获奖等级描述&#x27;</span>,
  sort_order <span class="hljs-type">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">&#x27;排序顺序&#x27;</span>,
  is_enabled TINYINT(<span class="hljs-number">1</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">1</span> COMMENT <span class="hljs-string">&#x27;是否启用(0:禁用 1:启用)&#x27;</span>,
  create_time DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;创建时间&#x27;</span>,
  update_time DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> <span class="hljs-keyword">ON</span> <span class="hljs-keyword">UPDATE</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;更新时间&#x27;</span>,
  create_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;创建者&#x27;</span>,
  update_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;更新者&#x27;</span>,
  remark <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">500</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;备注&#x27;</span>,
  <span class="hljs-keyword">PRIMARY</span> KEY (award_id),
  <span class="hljs-keyword">UNIQUE</span> INDEX uk_award_name (award_name),
  INDEX idx_is_enabled (is_enabled),
  INDEX idx_sort_order (sort_order)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8mb4 COMMENT<span class="hljs-operator">=</span><span class="hljs-string">&#x27;作品获奖等级表&#x27;</span>;

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> works (
  works_id <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;作品ID&#x27;</span>,
  title <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;作品标题&#x27;</span>,
  author <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;作者姓名&#x27;</span>,
  competition_id <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;关联的比赛活动ID&#x27;</span>,
  category_id <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;作品分类ID&#x27;</span>,
  award_id <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">6</span> COMMENT <span class="hljs-string">&#x27;获奖等级ID(默认未获奖)&#x27;</span>,
  tag_ids <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">200</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-string">&#x27;0&#x27;</span> COMMENT <span class="hljs-string">&#x27;标签ID列表(逗号分隔)&#x27;</span>,
  comment TEXT <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;作品评语&#x27;</span>,
  comment_display_length <span class="hljs-type">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">&#x27;评语展示字数&#x27;</span>,
  thumbnail_url <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">500</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;缩略图URL&#x27;</span>,
  create_time DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;创建时间&#x27;</span>,
  update_time DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> <span class="hljs-keyword">ON</span> <span class="hljs-keyword">UPDATE</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;更新时间&#x27;</span>,
  create_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;创建者&#x27;</span>,
  update_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;更新者&#x27;</span>,
  remark <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">500</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;备注&#x27;</span>,
  <span class="hljs-keyword">PRIMARY</span> KEY (works_id),
  INDEX idx_competition_id (competition_id),
  INDEX idx_category_id (category_id),
  INDEX idx_award_id (award_id),
  INDEX idx_author (author),
  INDEX idx_title (title),
  INDEX idx_create_time (create_time),
  INDEX idx_tag_ids (tag_ids)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8mb4 COMMENT<span class="hljs-operator">=</span><span class="hljs-string">&#x27;作品表&#x27;</span>;

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> works_image (
  image_id <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;图片ID&#x27;</span>,
  works_id <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;关联的作品ID&#x27;</span>,
  image_url <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">500</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;图片URL&#x27;</span>,
  thumbnail_url <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">500</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;缩略图URL&#x27;</span>,
  original_name <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;原始文件名&#x27;</span>,
  file_size <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;文件大小(字节)&#x27;</span>,
  sort_order <span class="hljs-type">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">&#x27;排序顺序&#x27;</span>,
  upload_time DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;上传时间&#x27;</span>,
  create_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;创建者&#x27;</span>,
  <span class="hljs-keyword">PRIMARY</span> KEY (image_id),
  INDEX idx_works_id (works_id),
  INDEX idx_sort_order (sort_order)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8mb4 COMMENT<span class="hljs-operator">=</span><span class="hljs-string">&#x27;作品图片表&#x27;</span>;

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> works_batch_upload (
  batch_id <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;批次ID&#x27;</span>,
  batch_name <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;批次名称&#x27;</span>,
  upload_id <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;上传任务ID&#x27;</span>,
  competition_id <span class="hljs-type">BIGINT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;比赛活动ID&#x27;</span>,
  total_works <span class="hljs-type">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">&#x27;作品总数&#x27;</span>,
  total_images <span class="hljs-type">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">&#x27;图片总数&#x27;</span>,
  status <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-string">&#x27;COMPLETED&#x27;</span> COMMENT <span class="hljs-string">&#x27;批次状态(COMPLETED/ROLLBACKED)&#x27;</span>,
  cos_urls TEXT <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;COS文件URL列表(JSON格式)&#x27;</span>,
  create_time DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;创建时间&#x27;</span>,
  create_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;创建者&#x27;</span>,
  rollback_time DATETIME <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;回滚时间&#x27;</span>,
  rollback_by <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">64</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;回滚操作者&#x27;</span>,
  rollback_reason <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">500</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;回滚原因&#x27;</span>,
  <span class="hljs-keyword">PRIMARY</span> KEY (batch_id),
  INDEX idx_upload_id (upload_id),
  INDEX idx_competition_id (competition_id),
  INDEX idx_status (status),
  INDEX idx_create_time (create_time)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8mb4 COMMENT<span class="hljs-operator">=</span><span class="hljs-string">&#x27;作品批次上传记录表&#x27;</span>;

<span class="hljs-comment">-- 插入初始数据</span>
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> works_tag (tag_id, tag_name, tag_description, sort_order) <span class="hljs-keyword">VALUES</span> 
(<span class="hljs-number">0</span>, <span class="hljs-string">&#x27;首页&#x27;</span>, <span class="hljs-string">&#x27;首页展示的作品&#x27;</span>, <span class="hljs-number">1</span>),
(<span class="hljs-number">1</span>, <span class="hljs-string">&#x27;优秀作品&#x27;</span>, <span class="hljs-string">&#x27;优秀作品展示&#x27;</span>, <span class="hljs-number">2</span>);

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> works_award (award_name, award_description, sort_order) <span class="hljs-keyword">VALUES</span> 
(<span class="hljs-string">&#x27;特等奖&#x27;</span>, <span class="hljs-string">&#x27;最高等级奖项&#x27;</span>, <span class="hljs-number">1</span>),
(<span class="hljs-string">&#x27;一等奖&#x27;</span>, <span class="hljs-string">&#x27;一等奖奖项&#x27;</span>, <span class="hljs-number">2</span>),
(<span class="hljs-string">&#x27;二等奖&#x27;</span>, <span class="hljs-string">&#x27;二等奖奖项&#x27;</span>, <span class="hljs-number">3</span>),
(<span class="hljs-string">&#x27;三等奖&#x27;</span>, <span class="hljs-string">&#x27;三等奖奖项&#x27;</span>, <span class="hljs-number">4</span>),
(<span class="hljs-string">&#x27;优秀奖&#x27;</span>, <span class="hljs-string">&#x27;优秀奖奖项&#x27;</span>, <span class="hljs-number">5</span>),
(<span class="hljs-string">&#x27;未获奖&#x27;</span>, <span class="hljs-string">&#x27;未获奖状态&#x27;</span>, <span class="hljs-number">6</span>);
</code></pre>
<hr>
<h2 id="测试用例">测试用例</h2>
<h3 id="正常流程测试">正常流程测试</h3>
<ol>
<li>
<p><strong>标签管理测试</strong></p>
<ul>
<li>创建新标签，验证唯一性约束</li>
<li>更新标签信息</li>
<li>查询标签列表，验证分页和排序</li>
</ul>
</li>
<li>
<p><strong>分类管理测试</strong></p>
<ul>
<li>创建新分类，验证唯一性约束</li>
<li>删除无引用的分类</li>
<li>尝试删除有引用的分类（应该失败）</li>
</ul>
</li>
<li>
<p><strong>获奖等级管理测试</strong></p>
<ul>
<li>创建新获奖等级</li>
<li>更新获奖等级信息</li>
<li>验证等级排序功能</li>
</ul>
</li>
<li>
<p><strong>作品批量上传测试</strong></p>
<ul>
<li>上传符合规范的压缩包</li>
<li>验证自动分类创建</li>
<li>验证重复作者检测</li>
<li>验证图片重命名和腾讯云COS上传</li>
</ul>
</li>
<li>
<p><strong>作品管理测试</strong></p>
<ul>
<li>查询作品列表，验证多条件筛选</li>
<li>获取作品详情</li>
<li>更新作品获奖等级</li>
<li>添加作品评语</li>
<li>删除作品及相关图片</li>
</ul>
</li>
<li>
<p><strong>App端访问测试</strong></p>
<ul>
<li>获取首页作品列表</li>
<li>获取优秀作品列表</li>
<li>获取作品详情</li>
<li>验证只能访问当前活动作品</li>
</ul>
</li>
</ol>
<h3 id="异常情况测试">异常情况测试</h3>
<ol>
<li>
<p><strong>参数验证测试</strong></p>
<ul>
<li>空标题、空作者、无效分类ID</li>
<li>超长评语、无效图片格式</li>
<li>压缩包格式错误、目录结构不规范</li>
</ul>
</li>
<li>
<p><strong>权限测试</strong></p>
<ul>
<li>非管理员访问管理接口</li>
<li>无效token访问</li>
</ul>
</li>
<li>
<p><strong>业务规则测试</strong></p>
<ul>
<li>删除有引用的分类</li>
<li>上传重复作品</li>
<li>腾讯云COS上传失败处理</li>
</ul>
</li>
<li>
<p><strong>文件处理测试</strong></p>
<ul>
<li>压缩包解压失败</li>
<li>图片格式不支持</li>
<li>文件大小超限(图片&gt;10MB, 压缩包&gt;1GB)</li>
<li>缩略图生成失败</li>
<li>大容量压缩包处理超时</li>
<li>内存不足处理大文件</li>
<li>压缩包内文件数量超限(&gt;50张图片)</li>
<li>网络中断时的断点续传</li>
<li>分块上传失败重试机制</li>
</ul>
</li>
</ol>
<h3 id="边界条件测试">边界条件测试</h3>
<ol>
<li>
<p><strong>数据边界</strong></p>
<ul>
<li>最大长度标题和作者名</li>
<li>最大图片文件大小(10MB)</li>
<li>最大压缩包大小(1GB)</li>
<li>最多图片数量(单个作品最多50张)</li>
</ul>
</li>
<li>
<p><strong>并发测试</strong></p>
<ul>
<li>同时上传多个压缩包</li>
<li>同时更新同一作品</li>
<li>同时删除和查询作品</li>
</ul>
</li>
<li>
<p><strong>性能测试</strong></p>
<ul>
<li>大量作品列表查询</li>
<li>大文件上传处理</li>
<li>缓存命中率测试</li>
<li>1GB压缩包上传性能测试</li>
<li>50张高清图片批量处理性能</li>
<li>并发大文件上传压力测试</li>
<li>内存使用率监控测试</li>
</ul>
</li>
</ol>
<hr>
<p><strong>注意：</strong> 当前版本为基础版本，支持作品的完整管理功能。预留功能包括：</p>
<ul>
<li>作品评论系统</li>
<li>作品点赞功能</li>
<li>作品分享功能</li>
<li>作品统计分析</li>
<li>批量导出功能</li>
<li>作品水印定制</li>
<li>多媒体作品支持</li>
</ul>
<p>这些功能将在后续版本中逐步实现。</p>
<hr>
<h2 id="更新日志">更新日志</h2>
<h3 id="v200-2024-12-29">v2.0.0 (2024-12-29)</h3>
<ul>
<li><strong>重大更新</strong>：实现分步骤批量上传机制</li>
<li><strong>压缩格式扩展</strong>：新增支持RAR、7Z格式，使用junrar库处理RAR文件</li>
<li><strong>存储迁移</strong>：完成从阿里云OSS到腾讯云COS的迁移</li>
<li><strong>并发控制</strong>：实现基于Redis的用户级并发限制(普通用户1个，管理员3个)</li>
<li><strong>进度监控</strong>：新增WebSocket实时进度推送功能</li>
<li><strong>批量回滚</strong>：实现完整的批量回滚机制，支持数据库、COS文件、缓存清理</li>
<li><strong>临时文件管理</strong>：优化临时文件清理策略，支持7天自动清理</li>
<li><strong>数据库扩展</strong>：新增works_batch_upload表支持批次管理</li>
<li><strong>配置优化</strong>：更新配置文件支持新功能特性</li>
<li><strong>错误码扩展</strong>：新增分步骤上传相关错误码(5029-5036)</li>
</ul>
<h3 id="v101-2024-12-28">v1.0.1 (2024-12-28)</h3>
<ul>
<li>调整最大压缩包大小限制从100MB提升至1GB</li>
<li>新增大文件处理策略和流式处理机制</li>
<li>增加压缩包内文件数量限制(最多50张图片)</li>
<li>新增大文件处理超时和内存不足错误码(5026, 5027, 5028)</li>
<li>优化大文件上传处理性能，采用分块上传</li>
<li>增强文件上传进度监控和断点续传支持</li>
<li>完善大容量压缩包的解压处理机制</li>
<li>新增JVM配置建议和Spring Boot大文件配置</li>
<li>增加大文件处理相关测试用例</li>
</ul>
<h3 id="v100-2024-12-28">v1.0.0 (2024-12-28)</h3>
<ul>
<li>初始版本发布</li>
<li>完整的作品管理功能</li>
<li>支持批量上传和腾讯云COS存储</li>
<li>实现Redis缓存优化</li>
<li>完善的权限控制和安全机制</li>
</ul>

            <script async src="https://cdn.jsdelivr.net/npm/katex-copytex@latest/dist/katex-copytex.min.js"></script>
            
        </body>
        </html>